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
114f141e36SHoratiu Vultur static int keyfield_size_table[] = {
124f141e36SHoratiu Vultur [VCAP_FIELD_BIT] = sizeof(struct vcap_u1_key),
134f141e36SHoratiu Vultur [VCAP_FIELD_U32] = sizeof(struct vcap_u32_key),
144f141e36SHoratiu Vultur [VCAP_FIELD_U48] = sizeof(struct vcap_u48_key),
154f141e36SHoratiu Vultur [VCAP_FIELD_U56] = sizeof(struct vcap_u56_key),
164f141e36SHoratiu Vultur [VCAP_FIELD_U64] = sizeof(struct vcap_u64_key),
174f141e36SHoratiu Vultur [VCAP_FIELD_U72] = sizeof(struct vcap_u72_key),
184f141e36SHoratiu Vultur [VCAP_FIELD_U112] = sizeof(struct vcap_u112_key),
194f141e36SHoratiu Vultur [VCAP_FIELD_U128] = sizeof(struct vcap_u128_key),
204f141e36SHoratiu Vultur };
214f141e36SHoratiu Vultur
224f141e36SHoratiu Vultur static int actionfield_size_table[] = {
234f141e36SHoratiu Vultur [VCAP_FIELD_BIT] = sizeof(struct vcap_u1_action),
244f141e36SHoratiu Vultur [VCAP_FIELD_U32] = sizeof(struct vcap_u32_action),
254f141e36SHoratiu Vultur [VCAP_FIELD_U48] = sizeof(struct vcap_u48_action),
264f141e36SHoratiu Vultur [VCAP_FIELD_U56] = sizeof(struct vcap_u56_action),
274f141e36SHoratiu Vultur [VCAP_FIELD_U64] = sizeof(struct vcap_u64_action),
284f141e36SHoratiu Vultur [VCAP_FIELD_U72] = sizeof(struct vcap_u72_action),
294f141e36SHoratiu Vultur [VCAP_FIELD_U112] = sizeof(struct vcap_u112_action),
304f141e36SHoratiu Vultur [VCAP_FIELD_U128] = sizeof(struct vcap_u128_action),
314f141e36SHoratiu Vultur };
324f141e36SHoratiu 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
40cfd9e7b7SSteen Hegelund /* Stores the filter cookie and chain id 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 */
45cfd9e7b7SSteen Hegelund int src_cid; /* source chain id */
46cfd9e7b7SSteen Hegelund int dst_cid; /* destination chain id */
4767456717SSteen Hegelund };
4867456717SSteen Hegelund
vcap_iter_set(struct vcap_stream_iter * itr,int sw_width,const struct vcap_typegroup * tg,u32 offset)49d4134d41SSteen Hegelund void vcap_iter_set(struct vcap_stream_iter *itr, int sw_width,
50683e05c0SSteen Hegelund const struct vcap_typegroup *tg, u32 offset)
51683e05c0SSteen Hegelund {
52683e05c0SSteen Hegelund memset(itr, 0, sizeof(*itr));
53683e05c0SSteen Hegelund itr->offset = offset;
54683e05c0SSteen Hegelund itr->sw_width = sw_width;
55683e05c0SSteen Hegelund itr->regs_per_sw = DIV_ROUND_UP(sw_width, 32);
56683e05c0SSteen Hegelund itr->tg = tg;
57683e05c0SSteen Hegelund }
58683e05c0SSteen Hegelund
vcap_iter_skip_tg(struct vcap_stream_iter * itr)59683e05c0SSteen Hegelund static void vcap_iter_skip_tg(struct vcap_stream_iter *itr)
60683e05c0SSteen Hegelund {
61683e05c0SSteen Hegelund /* Compensate the field offset for preceding typegroups.
62683e05c0SSteen Hegelund * A typegroup table ends with an all-zero terminator.
63683e05c0SSteen Hegelund */
64683e05c0SSteen Hegelund while (itr->tg->width && itr->offset >= itr->tg->offset) {
65683e05c0SSteen Hegelund itr->offset += itr->tg->width;
66683e05c0SSteen Hegelund itr->tg++; /* next typegroup */
67683e05c0SSteen Hegelund }
68683e05c0SSteen Hegelund }
69683e05c0SSteen Hegelund
vcap_iter_update(struct vcap_stream_iter * itr)70d4134d41SSteen Hegelund void vcap_iter_update(struct vcap_stream_iter *itr)
71683e05c0SSteen Hegelund {
72683e05c0SSteen Hegelund int sw_idx, sw_bitpos;
73683e05c0SSteen Hegelund
74683e05c0SSteen Hegelund /* Calculate the subword index and bitposition for current bit */
75683e05c0SSteen Hegelund sw_idx = itr->offset / itr->sw_width;
76683e05c0SSteen Hegelund sw_bitpos = itr->offset % itr->sw_width;
77683e05c0SSteen Hegelund /* Calculate the register index and bitposition for current bit */
78683e05c0SSteen Hegelund itr->reg_idx = (sw_idx * itr->regs_per_sw) + (sw_bitpos / 32);
79683e05c0SSteen Hegelund itr->reg_bitpos = sw_bitpos % 32;
80683e05c0SSteen Hegelund }
81683e05c0SSteen Hegelund
vcap_iter_init(struct vcap_stream_iter * itr,int sw_width,const struct vcap_typegroup * tg,u32 offset)82d4134d41SSteen Hegelund void vcap_iter_init(struct vcap_stream_iter *itr, int sw_width,
83683e05c0SSteen Hegelund const struct vcap_typegroup *tg, u32 offset)
84683e05c0SSteen Hegelund {
85683e05c0SSteen Hegelund vcap_iter_set(itr, sw_width, tg, offset);
86683e05c0SSteen Hegelund vcap_iter_skip_tg(itr);
87683e05c0SSteen Hegelund vcap_iter_update(itr);
88683e05c0SSteen Hegelund }
89683e05c0SSteen Hegelund
vcap_iter_next(struct vcap_stream_iter * itr)90d4134d41SSteen Hegelund void vcap_iter_next(struct vcap_stream_iter *itr)
91683e05c0SSteen Hegelund {
92683e05c0SSteen Hegelund itr->offset++;
93683e05c0SSteen Hegelund vcap_iter_skip_tg(itr);
94683e05c0SSteen Hegelund vcap_iter_update(itr);
95683e05c0SSteen Hegelund }
96683e05c0SSteen Hegelund
vcap_set_bit(u32 * stream,struct vcap_stream_iter * itr,bool value)97683e05c0SSteen Hegelund static void vcap_set_bit(u32 *stream, struct vcap_stream_iter *itr, bool value)
98683e05c0SSteen Hegelund {
99683e05c0SSteen Hegelund u32 mask = BIT(itr->reg_bitpos);
100683e05c0SSteen Hegelund u32 *p = &stream[itr->reg_idx];
101683e05c0SSteen Hegelund
102683e05c0SSteen Hegelund if (value)
103683e05c0SSteen Hegelund *p |= mask;
104683e05c0SSteen Hegelund else
105683e05c0SSteen Hegelund *p &= ~mask;
106683e05c0SSteen Hegelund }
107683e05c0SSteen Hegelund
vcap_encode_bit(u32 * stream,struct vcap_stream_iter * itr,bool val)108683e05c0SSteen Hegelund static void vcap_encode_bit(u32 *stream, struct vcap_stream_iter *itr, bool val)
109683e05c0SSteen Hegelund {
110683e05c0SSteen Hegelund /* When intersected by a type group field, stream the type group bits
111683e05c0SSteen Hegelund * before continuing with the value bit
112683e05c0SSteen Hegelund */
113683e05c0SSteen Hegelund while (itr->tg->width &&
114683e05c0SSteen Hegelund itr->offset >= itr->tg->offset &&
115683e05c0SSteen Hegelund itr->offset < itr->tg->offset + itr->tg->width) {
116683e05c0SSteen Hegelund int tg_bitpos = itr->tg->offset - itr->offset;
117683e05c0SSteen Hegelund
118683e05c0SSteen Hegelund vcap_set_bit(stream, itr, (itr->tg->value >> tg_bitpos) & 0x1);
119683e05c0SSteen Hegelund itr->offset++;
120683e05c0SSteen Hegelund vcap_iter_update(itr);
121683e05c0SSteen Hegelund }
122683e05c0SSteen Hegelund vcap_set_bit(stream, itr, val);
123683e05c0SSteen Hegelund }
124683e05c0SSteen Hegelund
vcap_encode_field(u32 * stream,struct vcap_stream_iter * itr,int width,const u8 * value)125683e05c0SSteen Hegelund static void vcap_encode_field(u32 *stream, struct vcap_stream_iter *itr,
126683e05c0SSteen Hegelund int width, const u8 *value)
127683e05c0SSteen Hegelund {
128683e05c0SSteen Hegelund int idx;
129683e05c0SSteen Hegelund
130683e05c0SSteen Hegelund /* Loop over the field value bits and add the value bits one by one to
131683e05c0SSteen Hegelund * the output stream.
132683e05c0SSteen Hegelund */
133683e05c0SSteen Hegelund for (idx = 0; idx < width; idx++) {
134683e05c0SSteen Hegelund u8 bidx = idx & GENMASK(2, 0);
135683e05c0SSteen Hegelund
136683e05c0SSteen Hegelund /* Encode one field value bit */
137683e05c0SSteen Hegelund vcap_encode_bit(stream, itr, (value[idx / 8] >> bidx) & 0x1);
138683e05c0SSteen Hegelund vcap_iter_next(itr);
139683e05c0SSteen Hegelund }
140683e05c0SSteen Hegelund }
141683e05c0SSteen Hegelund
vcap_encode_typegroups(u32 * stream,int sw_width,const struct vcap_typegroup * tg,bool mask)142683e05c0SSteen Hegelund static void vcap_encode_typegroups(u32 *stream, int sw_width,
143683e05c0SSteen Hegelund const struct vcap_typegroup *tg,
144683e05c0SSteen Hegelund bool mask)
145683e05c0SSteen Hegelund {
146683e05c0SSteen Hegelund struct vcap_stream_iter iter;
147683e05c0SSteen Hegelund int idx;
148683e05c0SSteen Hegelund
149683e05c0SSteen Hegelund /* Mask bits must be set to zeros (inverted later when writing to the
150683e05c0SSteen Hegelund * mask cache register), so that the mask typegroup bits consist of
151683e05c0SSteen Hegelund * match-1 or match-0, or both
152683e05c0SSteen Hegelund */
153683e05c0SSteen Hegelund vcap_iter_set(&iter, sw_width, tg, 0);
154683e05c0SSteen Hegelund while (iter.tg->width) {
155683e05c0SSteen Hegelund /* Set position to current typegroup bit */
156683e05c0SSteen Hegelund iter.offset = iter.tg->offset;
157683e05c0SSteen Hegelund vcap_iter_update(&iter);
158683e05c0SSteen Hegelund for (idx = 0; idx < iter.tg->width; idx++) {
159683e05c0SSteen Hegelund /* Iterate over current typegroup bits. Mask typegroup
160683e05c0SSteen Hegelund * bits are always set
161683e05c0SSteen Hegelund */
162683e05c0SSteen Hegelund if (mask)
163683e05c0SSteen Hegelund vcap_set_bit(stream, &iter, 0x1);
164683e05c0SSteen Hegelund else
165683e05c0SSteen Hegelund vcap_set_bit(stream, &iter,
166683e05c0SSteen Hegelund (iter.tg->value >> idx) & 0x1);
167683e05c0SSteen Hegelund iter.offset++;
168683e05c0SSteen Hegelund vcap_iter_update(&iter);
169683e05c0SSteen Hegelund }
170683e05c0SSteen Hegelund iter.tg++; /* next typegroup */
171683e05c0SSteen Hegelund }
172683e05c0SSteen Hegelund }
173683e05c0SSteen Hegelund
vcap_bitarray_zero(int width,u8 * value)174610c32b2SHoratiu Vultur static bool vcap_bitarray_zero(int width, u8 *value)
175610c32b2SHoratiu Vultur {
176610c32b2SHoratiu Vultur int bytes = DIV_ROUND_UP(width, BITS_PER_BYTE);
177610c32b2SHoratiu Vultur u8 total = 0, bmask = 0xff;
178610c32b2SHoratiu Vultur int rwidth = width;
179610c32b2SHoratiu Vultur int idx;
180610c32b2SHoratiu Vultur
181610c32b2SHoratiu Vultur for (idx = 0; idx < bytes; ++idx, rwidth -= BITS_PER_BYTE) {
182610c32b2SHoratiu Vultur if (rwidth && rwidth < BITS_PER_BYTE)
183610c32b2SHoratiu Vultur bmask = (1 << rwidth) - 1;
184610c32b2SHoratiu Vultur total += value[idx] & bmask;
185610c32b2SHoratiu Vultur }
186610c32b2SHoratiu Vultur return total == 0;
187610c32b2SHoratiu Vultur }
188610c32b2SHoratiu Vultur
vcap_get_bit(u32 * stream,struct vcap_stream_iter * itr)189610c32b2SHoratiu Vultur static bool vcap_get_bit(u32 *stream, struct vcap_stream_iter *itr)
190610c32b2SHoratiu Vultur {
191610c32b2SHoratiu Vultur u32 mask = BIT(itr->reg_bitpos);
192610c32b2SHoratiu Vultur u32 *p = &stream[itr->reg_idx];
193610c32b2SHoratiu Vultur
194610c32b2SHoratiu Vultur return !!(*p & mask);
195610c32b2SHoratiu Vultur }
196610c32b2SHoratiu Vultur
vcap_decode_field(u32 * stream,struct vcap_stream_iter * itr,int width,u8 * value)197610c32b2SHoratiu Vultur static void vcap_decode_field(u32 *stream, struct vcap_stream_iter *itr,
198610c32b2SHoratiu Vultur int width, u8 *value)
199610c32b2SHoratiu Vultur {
200610c32b2SHoratiu Vultur int idx;
201610c32b2SHoratiu Vultur
202610c32b2SHoratiu Vultur /* Loop over the field value bits and get the field bits and
203610c32b2SHoratiu Vultur * set them in the output value byte array
204610c32b2SHoratiu Vultur */
205610c32b2SHoratiu Vultur for (idx = 0; idx < width; idx++) {
206610c32b2SHoratiu Vultur u8 bidx = idx & 0x7;
207610c32b2SHoratiu Vultur
208610c32b2SHoratiu Vultur /* Decode one field value bit */
209610c32b2SHoratiu Vultur if (vcap_get_bit(stream, itr))
210610c32b2SHoratiu Vultur *value |= 1 << bidx;
211610c32b2SHoratiu Vultur vcap_iter_next(itr);
212610c32b2SHoratiu Vultur if (bidx == 7)
213610c32b2SHoratiu Vultur value++;
214610c32b2SHoratiu Vultur }
215610c32b2SHoratiu Vultur }
216610c32b2SHoratiu Vultur
217610c32b2SHoratiu Vultur /* Verify that the type id in the stream matches the type id of the keyset */
vcap_verify_keystream_keyset(struct vcap_control * vctrl,enum vcap_type vt,u32 * keystream,u32 * mskstream,enum vcap_keyfield_set keyset)218610c32b2SHoratiu Vultur static bool vcap_verify_keystream_keyset(struct vcap_control *vctrl,
219610c32b2SHoratiu Vultur enum vcap_type vt,
220610c32b2SHoratiu Vultur u32 *keystream,
221610c32b2SHoratiu Vultur u32 *mskstream,
222610c32b2SHoratiu Vultur enum vcap_keyfield_set keyset)
223610c32b2SHoratiu Vultur {
224610c32b2SHoratiu Vultur const struct vcap_info *vcap = &vctrl->vcaps[vt];
225610c32b2SHoratiu Vultur const struct vcap_field *typefld;
226610c32b2SHoratiu Vultur const struct vcap_typegroup *tgt;
227610c32b2SHoratiu Vultur const struct vcap_field *fields;
228610c32b2SHoratiu Vultur struct vcap_stream_iter iter;
229610c32b2SHoratiu Vultur const struct vcap_set *info;
230610c32b2SHoratiu Vultur u32 value = 0;
231610c32b2SHoratiu Vultur u32 mask = 0;
232610c32b2SHoratiu Vultur
233610c32b2SHoratiu Vultur if (vcap_keyfield_count(vctrl, vt, keyset) == 0)
234610c32b2SHoratiu Vultur return false;
235610c32b2SHoratiu Vultur
236610c32b2SHoratiu Vultur info = vcap_keyfieldset(vctrl, vt, keyset);
237610c32b2SHoratiu Vultur /* Check that the keyset is valid */
238610c32b2SHoratiu Vultur if (!info)
239610c32b2SHoratiu Vultur return false;
240610c32b2SHoratiu Vultur
241610c32b2SHoratiu Vultur /* a type_id of value -1 means that there is no type field */
242610c32b2SHoratiu Vultur if (info->type_id == (u8)-1)
243610c32b2SHoratiu Vultur return true;
244610c32b2SHoratiu Vultur
245610c32b2SHoratiu Vultur /* Get a valid typegroup for the specific keyset */
246610c32b2SHoratiu Vultur tgt = vcap_keyfield_typegroup(vctrl, vt, keyset);
247610c32b2SHoratiu Vultur if (!tgt)
248610c32b2SHoratiu Vultur return false;
249610c32b2SHoratiu Vultur
250610c32b2SHoratiu Vultur fields = vcap_keyfields(vctrl, vt, keyset);
251610c32b2SHoratiu Vultur if (!fields)
252610c32b2SHoratiu Vultur return false;
253610c32b2SHoratiu Vultur
254610c32b2SHoratiu Vultur typefld = &fields[VCAP_KF_TYPE];
255610c32b2SHoratiu Vultur vcap_iter_init(&iter, vcap->sw_width, tgt, typefld->offset);
256610c32b2SHoratiu Vultur vcap_decode_field(mskstream, &iter, typefld->width, (u8 *)&mask);
257610c32b2SHoratiu Vultur /* no type info if there are no mask bits */
258610c32b2SHoratiu Vultur if (vcap_bitarray_zero(typefld->width, (u8 *)&mask))
259610c32b2SHoratiu Vultur return false;
260610c32b2SHoratiu Vultur
261610c32b2SHoratiu Vultur /* Get the value of the type field in the stream and compare to the
262610c32b2SHoratiu Vultur * one define in the vcap keyset
263610c32b2SHoratiu Vultur */
264610c32b2SHoratiu Vultur vcap_iter_init(&iter, vcap->sw_width, tgt, typefld->offset);
265610c32b2SHoratiu Vultur vcap_decode_field(keystream, &iter, typefld->width, (u8 *)&value);
266610c32b2SHoratiu Vultur
267610c32b2SHoratiu Vultur return (value & mask) == (info->type_id & mask);
268610c32b2SHoratiu Vultur }
269610c32b2SHoratiu Vultur
270610c32b2SHoratiu Vultur /* Verify that the typegroup bits have the correct values */
vcap_verify_typegroups(u32 * stream,int sw_width,const struct vcap_typegroup * tgt,bool mask,int sw_max)271610c32b2SHoratiu Vultur static int vcap_verify_typegroups(u32 *stream, int sw_width,
272610c32b2SHoratiu Vultur const struct vcap_typegroup *tgt, bool mask,
273610c32b2SHoratiu Vultur int sw_max)
274610c32b2SHoratiu Vultur {
275610c32b2SHoratiu Vultur struct vcap_stream_iter iter;
276610c32b2SHoratiu Vultur int sw_cnt, idx;
277610c32b2SHoratiu Vultur
278610c32b2SHoratiu Vultur vcap_iter_set(&iter, sw_width, tgt, 0);
279610c32b2SHoratiu Vultur sw_cnt = 0;
280610c32b2SHoratiu Vultur while (iter.tg->width) {
281610c32b2SHoratiu Vultur u32 value = 0;
282610c32b2SHoratiu Vultur u32 tg_value = iter.tg->value;
283610c32b2SHoratiu Vultur
284610c32b2SHoratiu Vultur if (mask)
285610c32b2SHoratiu Vultur tg_value = (1 << iter.tg->width) - 1;
286610c32b2SHoratiu Vultur /* Set position to current typegroup bit */
287610c32b2SHoratiu Vultur iter.offset = iter.tg->offset;
288610c32b2SHoratiu Vultur vcap_iter_update(&iter);
289610c32b2SHoratiu Vultur for (idx = 0; idx < iter.tg->width; idx++) {
290610c32b2SHoratiu Vultur /* Decode one typegroup bit */
291610c32b2SHoratiu Vultur if (vcap_get_bit(stream, &iter))
292610c32b2SHoratiu Vultur value |= 1 << idx;
293610c32b2SHoratiu Vultur iter.offset++;
294610c32b2SHoratiu Vultur vcap_iter_update(&iter);
295610c32b2SHoratiu Vultur }
296610c32b2SHoratiu Vultur if (value != tg_value)
297610c32b2SHoratiu Vultur return -EINVAL;
298610c32b2SHoratiu Vultur iter.tg++; /* next typegroup */
299610c32b2SHoratiu Vultur sw_cnt++;
300610c32b2SHoratiu Vultur /* Stop checking more typegroups */
301610c32b2SHoratiu Vultur if (sw_max && sw_cnt >= sw_max)
302610c32b2SHoratiu Vultur break;
303610c32b2SHoratiu Vultur }
304610c32b2SHoratiu Vultur return 0;
305610c32b2SHoratiu Vultur }
306610c32b2SHoratiu Vultur
307610c32b2SHoratiu Vultur /* Find the subword width of the key typegroup that matches the stream data */
vcap_find_keystream_typegroup_sw(struct vcap_control * vctrl,enum vcap_type vt,u32 * stream,bool mask,int sw_max)308610c32b2SHoratiu Vultur static int vcap_find_keystream_typegroup_sw(struct vcap_control *vctrl,
309610c32b2SHoratiu Vultur enum vcap_type vt, u32 *stream,
310610c32b2SHoratiu Vultur bool mask, int sw_max)
311610c32b2SHoratiu Vultur {
312610c32b2SHoratiu Vultur const struct vcap_typegroup **tgt;
313610c32b2SHoratiu Vultur int sw_idx, res;
314610c32b2SHoratiu Vultur
315610c32b2SHoratiu Vultur tgt = vctrl->vcaps[vt].keyfield_set_typegroups;
316610c32b2SHoratiu Vultur /* Try the longest subword match first */
317610c32b2SHoratiu Vultur for (sw_idx = vctrl->vcaps[vt].sw_count; sw_idx >= 0; sw_idx--) {
318610c32b2SHoratiu Vultur if (!tgt[sw_idx])
319610c32b2SHoratiu Vultur continue;
320610c32b2SHoratiu Vultur
321610c32b2SHoratiu Vultur res = vcap_verify_typegroups(stream, vctrl->vcaps[vt].sw_width,
322610c32b2SHoratiu Vultur tgt[sw_idx], mask, sw_max);
323610c32b2SHoratiu Vultur if (res == 0)
324610c32b2SHoratiu Vultur return sw_idx;
325610c32b2SHoratiu Vultur }
326610c32b2SHoratiu Vultur return -EINVAL;
327610c32b2SHoratiu Vultur }
328610c32b2SHoratiu Vultur
329610c32b2SHoratiu Vultur /* Verify that the typegroup information, subword count, keyset and type id
330*d896a374SSimon Horman * are in sync and correct, return the list of matching keysets
331610c32b2SHoratiu Vultur */
332610c32b2SHoratiu Vultur int
vcap_find_keystream_keysets(struct vcap_control * vctrl,enum vcap_type vt,u32 * keystream,u32 * mskstream,bool mask,int sw_max,struct vcap_keyset_list * kslist)333610c32b2SHoratiu Vultur vcap_find_keystream_keysets(struct vcap_control *vctrl,
334610c32b2SHoratiu Vultur enum vcap_type vt,
335610c32b2SHoratiu Vultur u32 *keystream,
336610c32b2SHoratiu Vultur u32 *mskstream,
337610c32b2SHoratiu Vultur bool mask, int sw_max,
338610c32b2SHoratiu Vultur struct vcap_keyset_list *kslist)
339610c32b2SHoratiu Vultur {
340610c32b2SHoratiu Vultur const struct vcap_set *keyfield_set;
341610c32b2SHoratiu Vultur int sw_count, idx;
342610c32b2SHoratiu Vultur
343610c32b2SHoratiu Vultur sw_count = vcap_find_keystream_typegroup_sw(vctrl, vt, keystream, mask,
344610c32b2SHoratiu Vultur sw_max);
345610c32b2SHoratiu Vultur if (sw_count < 0)
346610c32b2SHoratiu Vultur return sw_count;
347610c32b2SHoratiu Vultur
348610c32b2SHoratiu Vultur keyfield_set = vctrl->vcaps[vt].keyfield_set;
349610c32b2SHoratiu Vultur for (idx = 0; idx < vctrl->vcaps[vt].keyfield_set_size; ++idx) {
350610c32b2SHoratiu Vultur if (keyfield_set[idx].sw_per_item != sw_count)
351610c32b2SHoratiu Vultur continue;
352610c32b2SHoratiu Vultur
353610c32b2SHoratiu Vultur if (vcap_verify_keystream_keyset(vctrl, vt, keystream,
354610c32b2SHoratiu Vultur mskstream, idx))
355610c32b2SHoratiu Vultur vcap_keyset_list_add(kslist, idx);
356610c32b2SHoratiu Vultur }
357610c32b2SHoratiu Vultur if (kslist->cnt > 0)
358610c32b2SHoratiu Vultur return 0;
359610c32b2SHoratiu Vultur return -EINVAL;
360610c32b2SHoratiu Vultur }
361610c32b2SHoratiu Vultur EXPORT_SYMBOL_GPL(vcap_find_keystream_keysets);
362610c32b2SHoratiu Vultur
363610c32b2SHoratiu Vultur /* Read key data from a VCAP address and discover if there are any rule keysets
364610c32b2SHoratiu Vultur * here
365610c32b2SHoratiu Vultur */
vcap_addr_keysets(struct vcap_control * vctrl,struct net_device * ndev,struct vcap_admin * admin,int addr,struct vcap_keyset_list * kslist)366610c32b2SHoratiu Vultur int vcap_addr_keysets(struct vcap_control *vctrl,
367610c32b2SHoratiu Vultur struct net_device *ndev,
368610c32b2SHoratiu Vultur struct vcap_admin *admin,
369610c32b2SHoratiu Vultur int addr,
370610c32b2SHoratiu Vultur struct vcap_keyset_list *kslist)
371610c32b2SHoratiu Vultur {
372610c32b2SHoratiu Vultur enum vcap_type vt = admin->vtype;
373610c32b2SHoratiu Vultur int keyset_sw_regs, idx;
374610c32b2SHoratiu Vultur u32 key = 0, mask = 0;
375610c32b2SHoratiu Vultur
376610c32b2SHoratiu Vultur /* Read the cache at the specified address */
377610c32b2SHoratiu Vultur keyset_sw_regs = DIV_ROUND_UP(vctrl->vcaps[vt].sw_width, 32);
378610c32b2SHoratiu Vultur vctrl->ops->update(ndev, admin, VCAP_CMD_READ, VCAP_SEL_ALL, addr);
379610c32b2SHoratiu Vultur vctrl->ops->cache_read(ndev, admin, VCAP_SEL_ENTRY, 0,
380610c32b2SHoratiu Vultur keyset_sw_regs);
381610c32b2SHoratiu Vultur /* Skip uninitialized key/mask entries */
382610c32b2SHoratiu Vultur for (idx = 0; idx < keyset_sw_regs; ++idx) {
383610c32b2SHoratiu Vultur key |= ~admin->cache.keystream[idx];
384610c32b2SHoratiu Vultur mask |= admin->cache.maskstream[idx];
385610c32b2SHoratiu Vultur }
386610c32b2SHoratiu Vultur if (key == 0 && mask == 0)
387610c32b2SHoratiu Vultur return -EINVAL;
388610c32b2SHoratiu Vultur /* Decode and locate the keysets */
389610c32b2SHoratiu Vultur return vcap_find_keystream_keysets(vctrl, vt, admin->cache.keystream,
390610c32b2SHoratiu Vultur admin->cache.maskstream, false, 0,
391610c32b2SHoratiu Vultur kslist);
392610c32b2SHoratiu Vultur }
393610c32b2SHoratiu Vultur EXPORT_SYMBOL_GPL(vcap_addr_keysets);
394610c32b2SHoratiu Vultur
39546be056eSSteen Hegelund /* Return the list of keyfields for the keyset */
vcap_keyfields(struct vcap_control * vctrl,enum vcap_type vt,enum vcap_keyfield_set keyset)396d4134d41SSteen Hegelund const struct vcap_field *vcap_keyfields(struct vcap_control *vctrl,
39746be056eSSteen Hegelund enum vcap_type vt,
39846be056eSSteen Hegelund enum vcap_keyfield_set keyset)
39946be056eSSteen Hegelund {
40046be056eSSteen Hegelund /* Check that the keyset exists in the vcap keyset list */
40146be056eSSteen Hegelund if (keyset >= vctrl->vcaps[vt].keyfield_set_size)
40246be056eSSteen Hegelund return NULL;
40346be056eSSteen Hegelund return vctrl->vcaps[vt].keyfield_set_map[keyset];
40446be056eSSteen Hegelund }
40546be056eSSteen Hegelund
4068e10490bSSteen Hegelund /* Return the keyset information for the keyset */
vcap_keyfieldset(struct vcap_control * vctrl,enum vcap_type vt,enum vcap_keyfield_set keyset)407d4134d41SSteen Hegelund const struct vcap_set *vcap_keyfieldset(struct vcap_control *vctrl,
4088e10490bSSteen Hegelund enum vcap_type vt,
4098e10490bSSteen Hegelund enum vcap_keyfield_set keyset)
4108e10490bSSteen Hegelund {
4118e10490bSSteen Hegelund const struct vcap_set *kset;
4128e10490bSSteen Hegelund
4138e10490bSSteen Hegelund /* Check that the keyset exists in the vcap keyset list */
4148e10490bSSteen Hegelund if (keyset >= vctrl->vcaps[vt].keyfield_set_size)
4158e10490bSSteen Hegelund return NULL;
4168e10490bSSteen Hegelund kset = &vctrl->vcaps[vt].keyfield_set[keyset];
4178e10490bSSteen Hegelund if (kset->sw_per_item == 0 || kset->sw_per_item > vctrl->vcaps[vt].sw_count)
4188e10490bSSteen Hegelund return NULL;
4198e10490bSSteen Hegelund return kset;
4208e10490bSSteen Hegelund }
421465a38a2SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_keyfieldset);
4228e10490bSSteen Hegelund
423683e05c0SSteen Hegelund /* Return the typegroup table for the matching keyset (using subword size) */
424d4134d41SSteen Hegelund const struct vcap_typegroup *
vcap_keyfield_typegroup(struct vcap_control * vctrl,enum vcap_type vt,enum vcap_keyfield_set keyset)425683e05c0SSteen Hegelund vcap_keyfield_typegroup(struct vcap_control *vctrl,
426683e05c0SSteen Hegelund enum vcap_type vt, enum vcap_keyfield_set keyset)
427683e05c0SSteen Hegelund {
428683e05c0SSteen Hegelund const struct vcap_set *kset = vcap_keyfieldset(vctrl, vt, keyset);
429683e05c0SSteen Hegelund
430683e05c0SSteen Hegelund /* Check that the keyset is valid */
431683e05c0SSteen Hegelund if (!kset)
432683e05c0SSteen Hegelund return NULL;
433683e05c0SSteen Hegelund return vctrl->vcaps[vt].keyfield_set_typegroups[kset->sw_per_item];
434683e05c0SSteen Hegelund }
435683e05c0SSteen Hegelund
436683e05c0SSteen Hegelund /* Return the number of keyfields in the keyset */
vcap_keyfield_count(struct vcap_control * vctrl,enum vcap_type vt,enum vcap_keyfield_set keyset)437d4134d41SSteen Hegelund int vcap_keyfield_count(struct vcap_control *vctrl,
438683e05c0SSteen Hegelund enum vcap_type vt, enum vcap_keyfield_set keyset)
439683e05c0SSteen Hegelund {
440683e05c0SSteen Hegelund /* Check that the keyset exists in the vcap keyset list */
441683e05c0SSteen Hegelund if (keyset >= vctrl->vcaps[vt].keyfield_set_size)
442683e05c0SSteen Hegelund return 0;
443683e05c0SSteen Hegelund return vctrl->vcaps[vt].keyfield_set_map_size[keyset];
444683e05c0SSteen Hegelund }
445683e05c0SSteen Hegelund
vcap_encode_keyfield(struct vcap_rule_internal * ri,const struct vcap_client_keyfield * kf,const struct vcap_field * rf,const struct vcap_typegroup * tgt)446683e05c0SSteen Hegelund static void vcap_encode_keyfield(struct vcap_rule_internal *ri,
447683e05c0SSteen Hegelund const struct vcap_client_keyfield *kf,
448683e05c0SSteen Hegelund const struct vcap_field *rf,
449683e05c0SSteen Hegelund const struct vcap_typegroup *tgt)
450683e05c0SSteen Hegelund {
451683e05c0SSteen Hegelund int sw_width = ri->vctrl->vcaps[ri->admin->vtype].sw_width;
452683e05c0SSteen Hegelund struct vcap_cache_data *cache = &ri->admin->cache;
453683e05c0SSteen Hegelund struct vcap_stream_iter iter;
454683e05c0SSteen Hegelund const u8 *value, *mask;
455683e05c0SSteen Hegelund
456683e05c0SSteen Hegelund /* Encode the fields for the key and the mask in their respective
457683e05c0SSteen Hegelund * streams, respecting the subword width.
458683e05c0SSteen Hegelund */
459683e05c0SSteen Hegelund switch (kf->ctrl.type) {
460683e05c0SSteen Hegelund case VCAP_FIELD_BIT:
461683e05c0SSteen Hegelund value = &kf->data.u1.value;
462683e05c0SSteen Hegelund mask = &kf->data.u1.mask;
463683e05c0SSteen Hegelund break;
464683e05c0SSteen Hegelund case VCAP_FIELD_U32:
465683e05c0SSteen Hegelund value = (const u8 *)&kf->data.u32.value;
466683e05c0SSteen Hegelund mask = (const u8 *)&kf->data.u32.mask;
467683e05c0SSteen Hegelund break;
468683e05c0SSteen Hegelund case VCAP_FIELD_U48:
469683e05c0SSteen Hegelund value = kf->data.u48.value;
470683e05c0SSteen Hegelund mask = kf->data.u48.mask;
471683e05c0SSteen Hegelund break;
472683e05c0SSteen Hegelund case VCAP_FIELD_U56:
473683e05c0SSteen Hegelund value = kf->data.u56.value;
474683e05c0SSteen Hegelund mask = kf->data.u56.mask;
475683e05c0SSteen Hegelund break;
476683e05c0SSteen Hegelund case VCAP_FIELD_U64:
477683e05c0SSteen Hegelund value = kf->data.u64.value;
478683e05c0SSteen Hegelund mask = kf->data.u64.mask;
479683e05c0SSteen Hegelund break;
480683e05c0SSteen Hegelund case VCAP_FIELD_U72:
481683e05c0SSteen Hegelund value = kf->data.u72.value;
482683e05c0SSteen Hegelund mask = kf->data.u72.mask;
483683e05c0SSteen Hegelund break;
484683e05c0SSteen Hegelund case VCAP_FIELD_U112:
485683e05c0SSteen Hegelund value = kf->data.u112.value;
486683e05c0SSteen Hegelund mask = kf->data.u112.mask;
487683e05c0SSteen Hegelund break;
488683e05c0SSteen Hegelund case VCAP_FIELD_U128:
489683e05c0SSteen Hegelund value = kf->data.u128.value;
490683e05c0SSteen Hegelund mask = kf->data.u128.mask;
491683e05c0SSteen Hegelund break;
492683e05c0SSteen Hegelund }
493683e05c0SSteen Hegelund vcap_iter_init(&iter, sw_width, tgt, rf->offset);
494683e05c0SSteen Hegelund vcap_encode_field(cache->keystream, &iter, rf->width, value);
495683e05c0SSteen Hegelund vcap_iter_init(&iter, sw_width, tgt, rf->offset);
496683e05c0SSteen Hegelund vcap_encode_field(cache->maskstream, &iter, rf->width, mask);
497683e05c0SSteen Hegelund }
498683e05c0SSteen Hegelund
vcap_encode_keyfield_typegroups(struct vcap_control * vctrl,struct vcap_rule_internal * ri,const struct vcap_typegroup * tgt)499683e05c0SSteen Hegelund static void vcap_encode_keyfield_typegroups(struct vcap_control *vctrl,
500683e05c0SSteen Hegelund struct vcap_rule_internal *ri,
501683e05c0SSteen Hegelund const struct vcap_typegroup *tgt)
502683e05c0SSteen Hegelund {
503683e05c0SSteen Hegelund int sw_width = vctrl->vcaps[ri->admin->vtype].sw_width;
504683e05c0SSteen Hegelund struct vcap_cache_data *cache = &ri->admin->cache;
505683e05c0SSteen Hegelund
506683e05c0SSteen Hegelund /* Encode the typegroup bits for the key and the mask in their streams,
507683e05c0SSteen Hegelund * respecting the subword width.
508683e05c0SSteen Hegelund */
509683e05c0SSteen Hegelund vcap_encode_typegroups(cache->keystream, sw_width, tgt, false);
510683e05c0SSteen Hegelund vcap_encode_typegroups(cache->maskstream, sw_width, tgt, true);
511683e05c0SSteen Hegelund }
512683e05c0SSteen Hegelund
51333e3a273SSteen Hegelund /* Copy data from src to dst but reverse the data in chunks of 32bits.
51433e3a273SSteen Hegelund * For example if src is 00:11:22:33:44:55 where 55 is LSB the dst will
51533e3a273SSteen Hegelund * have the value 22:33:44:55:00:11.
51633e3a273SSteen Hegelund */
vcap_copy_to_w32be(u8 * dst,const u8 * src,int size)51733e3a273SSteen Hegelund static void vcap_copy_to_w32be(u8 *dst, const u8 *src, int size)
51833e3a273SSteen Hegelund {
51933e3a273SSteen Hegelund for (int idx = 0; idx < size; ++idx) {
52033e3a273SSteen Hegelund int first_byte_index = 0;
52133e3a273SSteen Hegelund int nidx;
52233e3a273SSteen Hegelund
52333e3a273SSteen Hegelund first_byte_index = size - (((idx >> 2) + 1) << 2);
52433e3a273SSteen Hegelund if (first_byte_index < 0)
52533e3a273SSteen Hegelund first_byte_index = 0;
52633e3a273SSteen Hegelund nidx = idx + first_byte_index - (idx & ~0x3);
52733e3a273SSteen Hegelund dst[nidx] = src[idx];
52833e3a273SSteen Hegelund }
52933e3a273SSteen Hegelund }
53033e3a273SSteen Hegelund
53133e3a273SSteen Hegelund static void
vcap_copy_from_client_keyfield(struct vcap_rule * rule,struct vcap_client_keyfield * dst,const struct vcap_client_keyfield * src)53233e3a273SSteen Hegelund vcap_copy_from_client_keyfield(struct vcap_rule *rule,
53333e3a273SSteen Hegelund struct vcap_client_keyfield *dst,
53433e3a273SSteen Hegelund const struct vcap_client_keyfield *src)
53533e3a273SSteen Hegelund {
53633e3a273SSteen Hegelund struct vcap_rule_internal *ri = to_intrule(rule);
53733e3a273SSteen Hegelund const struct vcap_client_keyfield_data *sdata;
53833e3a273SSteen Hegelund struct vcap_client_keyfield_data *ddata;
53933e3a273SSteen Hegelund int size;
54033e3a273SSteen Hegelund
54133e3a273SSteen Hegelund dst->ctrl.type = src->ctrl.type;
54233e3a273SSteen Hegelund dst->ctrl.key = src->ctrl.key;
54333e3a273SSteen Hegelund INIT_LIST_HEAD(&dst->ctrl.list);
54433e3a273SSteen Hegelund sdata = &src->data;
54533e3a273SSteen Hegelund ddata = &dst->data;
54633e3a273SSteen Hegelund
54733e3a273SSteen Hegelund if (!ri->admin->w32be) {
54833e3a273SSteen Hegelund memcpy(ddata, sdata, sizeof(dst->data));
54933e3a273SSteen Hegelund return;
55033e3a273SSteen Hegelund }
55133e3a273SSteen Hegelund
55233e3a273SSteen Hegelund size = keyfield_size_table[dst->ctrl.type] / 2;
55333e3a273SSteen Hegelund
55433e3a273SSteen Hegelund switch (dst->ctrl.type) {
55533e3a273SSteen Hegelund case VCAP_FIELD_BIT:
55633e3a273SSteen Hegelund case VCAP_FIELD_U32:
55733e3a273SSteen Hegelund memcpy(ddata, sdata, sizeof(dst->data));
55833e3a273SSteen Hegelund break;
55933e3a273SSteen Hegelund case VCAP_FIELD_U48:
56033e3a273SSteen Hegelund vcap_copy_to_w32be(ddata->u48.value, src->data.u48.value, size);
56133e3a273SSteen Hegelund vcap_copy_to_w32be(ddata->u48.mask, src->data.u48.mask, size);
56233e3a273SSteen Hegelund break;
56333e3a273SSteen Hegelund case VCAP_FIELD_U56:
56433e3a273SSteen Hegelund vcap_copy_to_w32be(ddata->u56.value, sdata->u56.value, size);
56533e3a273SSteen Hegelund vcap_copy_to_w32be(ddata->u56.mask, sdata->u56.mask, size);
56633e3a273SSteen Hegelund break;
56733e3a273SSteen Hegelund case VCAP_FIELD_U64:
56833e3a273SSteen Hegelund vcap_copy_to_w32be(ddata->u64.value, sdata->u64.value, size);
56933e3a273SSteen Hegelund vcap_copy_to_w32be(ddata->u64.mask, sdata->u64.mask, size);
57033e3a273SSteen Hegelund break;
57133e3a273SSteen Hegelund case VCAP_FIELD_U72:
57233e3a273SSteen Hegelund vcap_copy_to_w32be(ddata->u72.value, sdata->u72.value, size);
57333e3a273SSteen Hegelund vcap_copy_to_w32be(ddata->u72.mask, sdata->u72.mask, size);
57433e3a273SSteen Hegelund break;
57533e3a273SSteen Hegelund case VCAP_FIELD_U112:
57633e3a273SSteen Hegelund vcap_copy_to_w32be(ddata->u112.value, sdata->u112.value, size);
57733e3a273SSteen Hegelund vcap_copy_to_w32be(ddata->u112.mask, sdata->u112.mask, size);
57833e3a273SSteen Hegelund break;
57933e3a273SSteen Hegelund case VCAP_FIELD_U128:
58033e3a273SSteen Hegelund vcap_copy_to_w32be(ddata->u128.value, sdata->u128.value, size);
58133e3a273SSteen Hegelund vcap_copy_to_w32be(ddata->u128.mask, sdata->u128.mask, size);
58233e3a273SSteen Hegelund break;
58333e3a273SSteen Hegelund }
58433e3a273SSteen Hegelund }
58533e3a273SSteen Hegelund
58633e3a273SSteen Hegelund static void
vcap_copy_from_client_actionfield(struct vcap_rule * rule,struct vcap_client_actionfield * dst,const struct vcap_client_actionfield * src)58733e3a273SSteen Hegelund vcap_copy_from_client_actionfield(struct vcap_rule *rule,
58833e3a273SSteen Hegelund struct vcap_client_actionfield *dst,
58933e3a273SSteen Hegelund const struct vcap_client_actionfield *src)
59033e3a273SSteen Hegelund {
59133e3a273SSteen Hegelund struct vcap_rule_internal *ri = to_intrule(rule);
59233e3a273SSteen Hegelund const struct vcap_client_actionfield_data *sdata;
59333e3a273SSteen Hegelund struct vcap_client_actionfield_data *ddata;
59433e3a273SSteen Hegelund int size;
59533e3a273SSteen Hegelund
59633e3a273SSteen Hegelund dst->ctrl.type = src->ctrl.type;
59733e3a273SSteen Hegelund dst->ctrl.action = src->ctrl.action;
59833e3a273SSteen Hegelund INIT_LIST_HEAD(&dst->ctrl.list);
59933e3a273SSteen Hegelund sdata = &src->data;
60033e3a273SSteen Hegelund ddata = &dst->data;
60133e3a273SSteen Hegelund
60233e3a273SSteen Hegelund if (!ri->admin->w32be) {
60333e3a273SSteen Hegelund memcpy(ddata, sdata, sizeof(dst->data));
60433e3a273SSteen Hegelund return;
60533e3a273SSteen Hegelund }
60633e3a273SSteen Hegelund
60733e3a273SSteen Hegelund size = actionfield_size_table[dst->ctrl.type];
60833e3a273SSteen Hegelund
60933e3a273SSteen Hegelund switch (dst->ctrl.type) {
61033e3a273SSteen Hegelund case VCAP_FIELD_BIT:
61133e3a273SSteen Hegelund case VCAP_FIELD_U32:
61233e3a273SSteen Hegelund memcpy(ddata, sdata, sizeof(dst->data));
61333e3a273SSteen Hegelund break;
61433e3a273SSteen Hegelund case VCAP_FIELD_U48:
61533e3a273SSteen Hegelund vcap_copy_to_w32be(ddata->u48.value, sdata->u48.value, size);
61633e3a273SSteen Hegelund break;
61733e3a273SSteen Hegelund case VCAP_FIELD_U56:
61833e3a273SSteen Hegelund vcap_copy_to_w32be(ddata->u56.value, sdata->u56.value, size);
61933e3a273SSteen Hegelund break;
62033e3a273SSteen Hegelund case VCAP_FIELD_U64:
62133e3a273SSteen Hegelund vcap_copy_to_w32be(ddata->u64.value, sdata->u64.value, size);
62233e3a273SSteen Hegelund break;
62333e3a273SSteen Hegelund case VCAP_FIELD_U72:
62433e3a273SSteen Hegelund vcap_copy_to_w32be(ddata->u72.value, sdata->u72.value, size);
62533e3a273SSteen Hegelund break;
62633e3a273SSteen Hegelund case VCAP_FIELD_U112:
62733e3a273SSteen Hegelund vcap_copy_to_w32be(ddata->u112.value, sdata->u112.value, size);
62833e3a273SSteen Hegelund break;
62933e3a273SSteen Hegelund case VCAP_FIELD_U128:
63033e3a273SSteen Hegelund vcap_copy_to_w32be(ddata->u128.value, sdata->u128.value, size);
63133e3a273SSteen Hegelund break;
63233e3a273SSteen Hegelund }
63333e3a273SSteen Hegelund }
63433e3a273SSteen Hegelund
vcap_encode_rule_keyset(struct vcap_rule_internal * ri)635683e05c0SSteen Hegelund static int vcap_encode_rule_keyset(struct vcap_rule_internal *ri)
636683e05c0SSteen Hegelund {
637683e05c0SSteen Hegelund const struct vcap_client_keyfield *ckf;
638683e05c0SSteen Hegelund const struct vcap_typegroup *tg_table;
63933e3a273SSteen Hegelund struct vcap_client_keyfield tempkf;
640683e05c0SSteen Hegelund const struct vcap_field *kf_table;
641683e05c0SSteen Hegelund int keyset_size;
642683e05c0SSteen Hegelund
643683e05c0SSteen Hegelund /* Get a valid set of fields for the specific keyset */
644683e05c0SSteen Hegelund kf_table = vcap_keyfields(ri->vctrl, ri->admin->vtype, ri->data.keyset);
645683e05c0SSteen Hegelund if (!kf_table) {
646683e05c0SSteen Hegelund pr_err("%s:%d: no fields available for this keyset: %d\n",
647683e05c0SSteen Hegelund __func__, __LINE__, ri->data.keyset);
648683e05c0SSteen Hegelund return -EINVAL;
649683e05c0SSteen Hegelund }
650683e05c0SSteen Hegelund /* Get a valid typegroup for the specific keyset */
651683e05c0SSteen Hegelund tg_table = vcap_keyfield_typegroup(ri->vctrl, ri->admin->vtype,
652683e05c0SSteen Hegelund ri->data.keyset);
653683e05c0SSteen Hegelund if (!tg_table) {
654683e05c0SSteen Hegelund pr_err("%s:%d: no typegroups available for this keyset: %d\n",
655683e05c0SSteen Hegelund __func__, __LINE__, ri->data.keyset);
656683e05c0SSteen Hegelund return -EINVAL;
657683e05c0SSteen Hegelund }
658683e05c0SSteen Hegelund /* Get a valid size for the specific keyset */
659683e05c0SSteen Hegelund keyset_size = vcap_keyfield_count(ri->vctrl, ri->admin->vtype,
660683e05c0SSteen Hegelund ri->data.keyset);
661683e05c0SSteen Hegelund if (keyset_size == 0) {
662683e05c0SSteen Hegelund pr_err("%s:%d: zero field count for this keyset: %d\n",
663683e05c0SSteen Hegelund __func__, __LINE__, ri->data.keyset);
664683e05c0SSteen Hegelund return -EINVAL;
665683e05c0SSteen Hegelund }
666683e05c0SSteen Hegelund /* Iterate over the keyfields (key, mask) in the rule
667683e05c0SSteen Hegelund * and encode these bits
668683e05c0SSteen Hegelund */
669683e05c0SSteen Hegelund if (list_empty(&ri->data.keyfields)) {
670683e05c0SSteen Hegelund pr_err("%s:%d: no keyfields in the rule\n", __func__, __LINE__);
671683e05c0SSteen Hegelund return -EINVAL;
672683e05c0SSteen Hegelund }
673683e05c0SSteen Hegelund list_for_each_entry(ckf, &ri->data.keyfields, ctrl.list) {
674683e05c0SSteen Hegelund /* Check that the client entry exists in the keyset */
675683e05c0SSteen Hegelund if (ckf->ctrl.key >= keyset_size) {
676683e05c0SSteen Hegelund pr_err("%s:%d: key %d is not in vcap\n",
677683e05c0SSteen Hegelund __func__, __LINE__, ckf->ctrl.key);
678683e05c0SSteen Hegelund return -EINVAL;
679683e05c0SSteen Hegelund }
68033e3a273SSteen Hegelund vcap_copy_from_client_keyfield(&ri->data, &tempkf, ckf);
68133e3a273SSteen Hegelund vcap_encode_keyfield(ri, &tempkf, &kf_table[ckf->ctrl.key],
68233e3a273SSteen Hegelund tg_table);
683683e05c0SSteen Hegelund }
684683e05c0SSteen Hegelund /* Add typegroup bits to the key/mask bitstreams */
685683e05c0SSteen Hegelund vcap_encode_keyfield_typegroups(ri->vctrl, ri, tg_table);
686683e05c0SSteen Hegelund return 0;
687683e05c0SSteen Hegelund }
688683e05c0SSteen Hegelund
689683e05c0SSteen Hegelund /* Return the list of actionfields for the actionset */
69072d84dd6SSteen Hegelund const struct vcap_field *
vcap_actionfields(struct vcap_control * vctrl,enum vcap_type vt,enum vcap_actionfield_set actionset)691683e05c0SSteen Hegelund vcap_actionfields(struct vcap_control *vctrl,
692683e05c0SSteen Hegelund enum vcap_type vt, enum vcap_actionfield_set actionset)
693683e05c0SSteen Hegelund {
694683e05c0SSteen Hegelund /* Check that the actionset exists in the vcap actionset list */
695683e05c0SSteen Hegelund if (actionset >= vctrl->vcaps[vt].actionfield_set_size)
696683e05c0SSteen Hegelund return NULL;
697683e05c0SSteen Hegelund return vctrl->vcaps[vt].actionfield_set_map[actionset];
698683e05c0SSteen Hegelund }
699683e05c0SSteen Hegelund
70072d84dd6SSteen Hegelund const struct vcap_set *
vcap_actionfieldset(struct vcap_control * vctrl,enum vcap_type vt,enum vcap_actionfield_set actionset)7018e10490bSSteen Hegelund vcap_actionfieldset(struct vcap_control *vctrl,
7028e10490bSSteen Hegelund enum vcap_type vt, enum vcap_actionfield_set actionset)
7038e10490bSSteen Hegelund {
7048e10490bSSteen Hegelund const struct vcap_set *aset;
7058e10490bSSteen Hegelund
7068e10490bSSteen Hegelund /* Check that the actionset exists in the vcap actionset list */
7078e10490bSSteen Hegelund if (actionset >= vctrl->vcaps[vt].actionfield_set_size)
7088e10490bSSteen Hegelund return NULL;
7098e10490bSSteen Hegelund aset = &vctrl->vcaps[vt].actionfield_set[actionset];
7108e10490bSSteen Hegelund if (aset->sw_per_item == 0 || aset->sw_per_item > vctrl->vcaps[vt].sw_count)
7118e10490bSSteen Hegelund return NULL;
7128e10490bSSteen Hegelund return aset;
7138e10490bSSteen Hegelund }
7148e10490bSSteen Hegelund
715683e05c0SSteen Hegelund /* Return the typegroup table for the matching actionset (using subword size) */
71672d84dd6SSteen Hegelund const struct vcap_typegroup *
vcap_actionfield_typegroup(struct vcap_control * vctrl,enum vcap_type vt,enum vcap_actionfield_set actionset)717683e05c0SSteen Hegelund vcap_actionfield_typegroup(struct vcap_control *vctrl,
718683e05c0SSteen Hegelund enum vcap_type vt, enum vcap_actionfield_set actionset)
719683e05c0SSteen Hegelund {
720683e05c0SSteen Hegelund const struct vcap_set *aset = vcap_actionfieldset(vctrl, vt, actionset);
721683e05c0SSteen Hegelund
722683e05c0SSteen Hegelund /* Check that the actionset is valid */
723683e05c0SSteen Hegelund if (!aset)
724683e05c0SSteen Hegelund return NULL;
725683e05c0SSteen Hegelund return vctrl->vcaps[vt].actionfield_set_typegroups[aset->sw_per_item];
726683e05c0SSteen Hegelund }
727683e05c0SSteen Hegelund
728683e05c0SSteen Hegelund /* Return the number of actionfields in the actionset */
vcap_actionfield_count(struct vcap_control * vctrl,enum vcap_type vt,enum vcap_actionfield_set actionset)72972d84dd6SSteen Hegelund int vcap_actionfield_count(struct vcap_control *vctrl,
730683e05c0SSteen Hegelund enum vcap_type vt,
731683e05c0SSteen Hegelund enum vcap_actionfield_set actionset)
732683e05c0SSteen Hegelund {
733683e05c0SSteen Hegelund /* Check that the actionset exists in the vcap actionset list */
734683e05c0SSteen Hegelund if (actionset >= vctrl->vcaps[vt].actionfield_set_size)
735683e05c0SSteen Hegelund return 0;
736683e05c0SSteen Hegelund return vctrl->vcaps[vt].actionfield_set_map_size[actionset];
737683e05c0SSteen Hegelund }
738683e05c0SSteen Hegelund
vcap_encode_actionfield(struct vcap_rule_internal * ri,const struct vcap_client_actionfield * af,const struct vcap_field * rf,const struct vcap_typegroup * tgt)739683e05c0SSteen Hegelund static void vcap_encode_actionfield(struct vcap_rule_internal *ri,
740683e05c0SSteen Hegelund const struct vcap_client_actionfield *af,
741683e05c0SSteen Hegelund const struct vcap_field *rf,
742683e05c0SSteen Hegelund const struct vcap_typegroup *tgt)
743683e05c0SSteen Hegelund {
744683e05c0SSteen Hegelund int act_width = ri->vctrl->vcaps[ri->admin->vtype].act_width;
745683e05c0SSteen Hegelund
746683e05c0SSteen Hegelund struct vcap_cache_data *cache = &ri->admin->cache;
747683e05c0SSteen Hegelund struct vcap_stream_iter iter;
748683e05c0SSteen Hegelund const u8 *value;
749683e05c0SSteen Hegelund
750683e05c0SSteen Hegelund /* Encode the action field in the stream, respecting the subword width */
751683e05c0SSteen Hegelund switch (af->ctrl.type) {
752683e05c0SSteen Hegelund case VCAP_FIELD_BIT:
753683e05c0SSteen Hegelund value = &af->data.u1.value;
754683e05c0SSteen Hegelund break;
755683e05c0SSteen Hegelund case VCAP_FIELD_U32:
756683e05c0SSteen Hegelund value = (const u8 *)&af->data.u32.value;
757683e05c0SSteen Hegelund break;
758683e05c0SSteen Hegelund case VCAP_FIELD_U48:
759683e05c0SSteen Hegelund value = af->data.u48.value;
760683e05c0SSteen Hegelund break;
761683e05c0SSteen Hegelund case VCAP_FIELD_U56:
762683e05c0SSteen Hegelund value = af->data.u56.value;
763683e05c0SSteen Hegelund break;
764683e05c0SSteen Hegelund case VCAP_FIELD_U64:
765683e05c0SSteen Hegelund value = af->data.u64.value;
766683e05c0SSteen Hegelund break;
767683e05c0SSteen Hegelund case VCAP_FIELD_U72:
768683e05c0SSteen Hegelund value = af->data.u72.value;
769683e05c0SSteen Hegelund break;
770683e05c0SSteen Hegelund case VCAP_FIELD_U112:
771683e05c0SSteen Hegelund value = af->data.u112.value;
772683e05c0SSteen Hegelund break;
773683e05c0SSteen Hegelund case VCAP_FIELD_U128:
774683e05c0SSteen Hegelund value = af->data.u128.value;
775683e05c0SSteen Hegelund break;
776683e05c0SSteen Hegelund }
777683e05c0SSteen Hegelund vcap_iter_init(&iter, act_width, tgt, rf->offset);
778683e05c0SSteen Hegelund vcap_encode_field(cache->actionstream, &iter, rf->width, value);
779683e05c0SSteen Hegelund }
780683e05c0SSteen Hegelund
vcap_encode_actionfield_typegroups(struct vcap_rule_internal * ri,const struct vcap_typegroup * tgt)781683e05c0SSteen Hegelund static void vcap_encode_actionfield_typegroups(struct vcap_rule_internal *ri,
782683e05c0SSteen Hegelund const struct vcap_typegroup *tgt)
783683e05c0SSteen Hegelund {
784683e05c0SSteen Hegelund int sw_width = ri->vctrl->vcaps[ri->admin->vtype].act_width;
785683e05c0SSteen Hegelund struct vcap_cache_data *cache = &ri->admin->cache;
786683e05c0SSteen Hegelund
787683e05c0SSteen Hegelund /* Encode the typegroup bits for the actionstream respecting the subword
788683e05c0SSteen Hegelund * width.
789683e05c0SSteen Hegelund */
790683e05c0SSteen Hegelund vcap_encode_typegroups(cache->actionstream, sw_width, tgt, false);
791683e05c0SSteen Hegelund }
792683e05c0SSteen Hegelund
vcap_encode_rule_actionset(struct vcap_rule_internal * ri)793683e05c0SSteen Hegelund static int vcap_encode_rule_actionset(struct vcap_rule_internal *ri)
794683e05c0SSteen Hegelund {
795683e05c0SSteen Hegelund const struct vcap_client_actionfield *caf;
796683e05c0SSteen Hegelund const struct vcap_typegroup *tg_table;
79733e3a273SSteen Hegelund struct vcap_client_actionfield tempaf;
798683e05c0SSteen Hegelund const struct vcap_field *af_table;
799683e05c0SSteen Hegelund int actionset_size;
800683e05c0SSteen Hegelund
801683e05c0SSteen Hegelund /* Get a valid set of actionset fields for the specific actionset */
802683e05c0SSteen Hegelund af_table = vcap_actionfields(ri->vctrl, ri->admin->vtype,
803683e05c0SSteen Hegelund ri->data.actionset);
804683e05c0SSteen Hegelund if (!af_table) {
805683e05c0SSteen Hegelund pr_err("%s:%d: no fields available for this actionset: %d\n",
806683e05c0SSteen Hegelund __func__, __LINE__, ri->data.actionset);
807683e05c0SSteen Hegelund return -EINVAL;
808683e05c0SSteen Hegelund }
809683e05c0SSteen Hegelund /* Get a valid typegroup for the specific actionset */
810683e05c0SSteen Hegelund tg_table = vcap_actionfield_typegroup(ri->vctrl, ri->admin->vtype,
811683e05c0SSteen Hegelund ri->data.actionset);
812683e05c0SSteen Hegelund if (!tg_table) {
813683e05c0SSteen Hegelund pr_err("%s:%d: no typegroups available for this actionset: %d\n",
814683e05c0SSteen Hegelund __func__, __LINE__, ri->data.actionset);
815683e05c0SSteen Hegelund return -EINVAL;
816683e05c0SSteen Hegelund }
817683e05c0SSteen Hegelund /* Get a valid actionset size for the specific actionset */
818683e05c0SSteen Hegelund actionset_size = vcap_actionfield_count(ri->vctrl, ri->admin->vtype,
819683e05c0SSteen Hegelund ri->data.actionset);
820683e05c0SSteen Hegelund if (actionset_size == 0) {
821683e05c0SSteen Hegelund pr_err("%s:%d: zero field count for this actionset: %d\n",
822683e05c0SSteen Hegelund __func__, __LINE__, ri->data.actionset);
823683e05c0SSteen Hegelund return -EINVAL;
824683e05c0SSteen Hegelund }
825683e05c0SSteen Hegelund /* Iterate over the actionfields in the rule
826683e05c0SSteen Hegelund * and encode these bits
827683e05c0SSteen Hegelund */
828683e05c0SSteen Hegelund if (list_empty(&ri->data.actionfields))
829683e05c0SSteen Hegelund pr_warn("%s:%d: no actionfields in the rule\n",
830683e05c0SSteen Hegelund __func__, __LINE__);
831683e05c0SSteen Hegelund list_for_each_entry(caf, &ri->data.actionfields, ctrl.list) {
832683e05c0SSteen Hegelund /* Check that the client action exists in the actionset */
833683e05c0SSteen Hegelund if (caf->ctrl.action >= actionset_size) {
834683e05c0SSteen Hegelund pr_err("%s:%d: action %d is not in vcap\n",
835683e05c0SSteen Hegelund __func__, __LINE__, caf->ctrl.action);
836683e05c0SSteen Hegelund return -EINVAL;
837683e05c0SSteen Hegelund }
83833e3a273SSteen Hegelund vcap_copy_from_client_actionfield(&ri->data, &tempaf, caf);
83933e3a273SSteen Hegelund vcap_encode_actionfield(ri, &tempaf,
84033e3a273SSteen Hegelund &af_table[caf->ctrl.action], tg_table);
841683e05c0SSteen Hegelund }
842683e05c0SSteen Hegelund /* Add typegroup bits to the entry bitstreams */
843683e05c0SSteen Hegelund vcap_encode_actionfield_typegroups(ri, tg_table);
844683e05c0SSteen Hegelund return 0;
845683e05c0SSteen Hegelund }
846683e05c0SSteen Hegelund
vcap_encode_rule(struct vcap_rule_internal * ri)8478e10490bSSteen Hegelund static int vcap_encode_rule(struct vcap_rule_internal *ri)
8488e10490bSSteen Hegelund {
849683e05c0SSteen Hegelund int err;
850683e05c0SSteen Hegelund
851683e05c0SSteen Hegelund err = vcap_encode_rule_keyset(ri);
852683e05c0SSteen Hegelund if (err)
853683e05c0SSteen Hegelund return err;
854683e05c0SSteen Hegelund err = vcap_encode_rule_actionset(ri);
855683e05c0SSteen Hegelund if (err)
856683e05c0SSteen Hegelund return err;
8578e10490bSSteen Hegelund return 0;
8588e10490bSSteen Hegelund }
8598e10490bSSteen Hegelund
vcap_api_check(struct vcap_control * ctrl)860d4134d41SSteen Hegelund int vcap_api_check(struct vcap_control *ctrl)
8618e10490bSSteen Hegelund {
8628e10490bSSteen Hegelund if (!ctrl) {
8638e10490bSSteen Hegelund pr_err("%s:%d: vcap control is missing\n", __func__, __LINE__);
8648e10490bSSteen Hegelund return -EINVAL;
8658e10490bSSteen Hegelund }
8668e10490bSSteen Hegelund if (!ctrl->ops || !ctrl->ops->validate_keyset ||
8678e10490bSSteen Hegelund !ctrl->ops->add_default_fields || !ctrl->ops->cache_erase ||
8688e10490bSSteen Hegelund !ctrl->ops->cache_write || !ctrl->ops->cache_read ||
8698e10490bSSteen Hegelund !ctrl->ops->init || !ctrl->ops->update || !ctrl->ops->move ||
87001ef75a2SSteen Hegelund !ctrl->ops->port_info) {
8718e10490bSSteen Hegelund pr_err("%s:%d: client operations are missing\n",
8728e10490bSSteen Hegelund __func__, __LINE__);
8738e10490bSSteen Hegelund return -ENOENT;
8748e10490bSSteen Hegelund }
8758e10490bSSteen Hegelund return 0;
8768e10490bSSteen Hegelund }
8778e10490bSSteen Hegelund
vcap_erase_cache(struct vcap_rule_internal * ri)8783a792156SSteen Hegelund void vcap_erase_cache(struct vcap_rule_internal *ri)
8798e10490bSSteen Hegelund {
8808e10490bSSteen Hegelund ri->vctrl->ops->cache_erase(ri->admin);
8818e10490bSSteen Hegelund }
8828e10490bSSteen Hegelund
883c9da1ac1SSteen Hegelund /* Update the keyset for the rule */
vcap_set_rule_set_keyset(struct vcap_rule * rule,enum vcap_keyfield_set keyset)884c9da1ac1SSteen Hegelund int vcap_set_rule_set_keyset(struct vcap_rule *rule,
885c9da1ac1SSteen Hegelund enum vcap_keyfield_set keyset)
886c9da1ac1SSteen Hegelund {
8878e10490bSSteen Hegelund struct vcap_rule_internal *ri = to_intrule(rule);
8888e10490bSSteen Hegelund const struct vcap_set *kset;
8898e10490bSSteen Hegelund int sw_width;
8908e10490bSSteen Hegelund
8918e10490bSSteen Hegelund kset = vcap_keyfieldset(ri->vctrl, ri->admin->vtype, keyset);
8928e10490bSSteen Hegelund /* Check that the keyset is valid */
8938e10490bSSteen Hegelund if (!kset)
8948e10490bSSteen Hegelund return -EINVAL;
8958e10490bSSteen Hegelund ri->keyset_sw = kset->sw_per_item;
8968e10490bSSteen Hegelund sw_width = ri->vctrl->vcaps[ri->admin->vtype].sw_width;
8978e10490bSSteen Hegelund ri->keyset_sw_regs = DIV_ROUND_UP(sw_width, 32);
8988e10490bSSteen Hegelund ri->data.keyset = keyset;
899c9da1ac1SSteen Hegelund return 0;
900c9da1ac1SSteen Hegelund }
901c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_set_rule_set_keyset);
902c9da1ac1SSteen Hegelund
903c9da1ac1SSteen Hegelund /* Update the actionset for the rule */
vcap_set_rule_set_actionset(struct vcap_rule * rule,enum vcap_actionfield_set actionset)904c9da1ac1SSteen Hegelund int vcap_set_rule_set_actionset(struct vcap_rule *rule,
905c9da1ac1SSteen Hegelund enum vcap_actionfield_set actionset)
906c9da1ac1SSteen Hegelund {
9078e10490bSSteen Hegelund struct vcap_rule_internal *ri = to_intrule(rule);
9088e10490bSSteen Hegelund const struct vcap_set *aset;
9098e10490bSSteen Hegelund int act_width;
9108e10490bSSteen Hegelund
9118e10490bSSteen Hegelund aset = vcap_actionfieldset(ri->vctrl, ri->admin->vtype, actionset);
9128e10490bSSteen Hegelund /* Check that the actionset is valid */
9138e10490bSSteen Hegelund if (!aset)
9148e10490bSSteen Hegelund return -EINVAL;
9158e10490bSSteen Hegelund ri->actionset_sw = aset->sw_per_item;
9168e10490bSSteen Hegelund act_width = ri->vctrl->vcaps[ri->admin->vtype].act_width;
9178e10490bSSteen Hegelund ri->actionset_sw_regs = DIV_ROUND_UP(act_width, 32);
9188e10490bSSteen Hegelund ri->data.actionset = actionset;
919c9da1ac1SSteen Hegelund return 0;
920c9da1ac1SSteen Hegelund }
921c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_set_rule_set_actionset);
922c9da1ac1SSteen Hegelund
923975d86acSSteen Hegelund /* Check if a rule with this id exists */
vcap_rule_exists(struct vcap_control * vctrl,u32 id)924975d86acSSteen Hegelund static bool vcap_rule_exists(struct vcap_control *vctrl, u32 id)
925975d86acSSteen Hegelund {
926975d86acSSteen Hegelund struct vcap_rule_internal *ri;
927975d86acSSteen Hegelund struct vcap_admin *admin;
928975d86acSSteen Hegelund
929975d86acSSteen Hegelund /* Look for the rule id in all vcaps */
930975d86acSSteen Hegelund list_for_each_entry(admin, &vctrl->list, list)
931975d86acSSteen Hegelund list_for_each_entry(ri, &admin->rules, list)
932975d86acSSteen Hegelund if (ri->data.id == id)
933975d86acSSteen Hegelund return true;
934975d86acSSteen Hegelund return false;
935975d86acSSteen Hegelund }
936975d86acSSteen Hegelund
9371972b6d9SSteen Hegelund /* Find a rule with a provided rule id return a locked vcap */
9381972b6d9SSteen Hegelund static struct vcap_rule_internal *
vcap_get_locked_rule(struct vcap_control * vctrl,u32 id)9391972b6d9SSteen Hegelund vcap_get_locked_rule(struct vcap_control *vctrl, u32 id)
940c9da1ac1SSteen Hegelund {
941c9da1ac1SSteen Hegelund struct vcap_rule_internal *ri;
942c9da1ac1SSteen Hegelund struct vcap_admin *admin;
943c9da1ac1SSteen Hegelund
944c9da1ac1SSteen Hegelund /* Look for the rule id in all vcaps */
9451972b6d9SSteen Hegelund list_for_each_entry(admin, &vctrl->list, list) {
9461972b6d9SSteen Hegelund mutex_lock(&admin->lock);
947c9da1ac1SSteen Hegelund list_for_each_entry(ri, &admin->rules, list)
948c9da1ac1SSteen Hegelund if (ri->data.id == id)
949c9da1ac1SSteen Hegelund return ri;
9501972b6d9SSteen Hegelund mutex_unlock(&admin->lock);
9511972b6d9SSteen Hegelund }
952c9da1ac1SSteen Hegelund return NULL;
953c9da1ac1SSteen Hegelund }
954c9da1ac1SSteen Hegelund
955c9da1ac1SSteen Hegelund /* Find a rule id with a provided cookie */
vcap_lookup_rule_by_cookie(struct vcap_control * vctrl,u64 cookie)956c9da1ac1SSteen Hegelund int vcap_lookup_rule_by_cookie(struct vcap_control *vctrl, u64 cookie)
957c9da1ac1SSteen Hegelund {
958c9da1ac1SSteen Hegelund struct vcap_rule_internal *ri;
959c9da1ac1SSteen Hegelund struct vcap_admin *admin;
9601972b6d9SSteen Hegelund int id = 0;
961c9da1ac1SSteen Hegelund
962c9da1ac1SSteen Hegelund /* Look for the rule id in all vcaps */
9631972b6d9SSteen Hegelund list_for_each_entry(admin, &vctrl->list, list) {
9641972b6d9SSteen Hegelund mutex_lock(&admin->lock);
9651972b6d9SSteen Hegelund list_for_each_entry(ri, &admin->rules, list) {
9661972b6d9SSteen Hegelund if (ri->data.cookie == cookie) {
9671972b6d9SSteen Hegelund id = ri->data.id;
9681972b6d9SSteen Hegelund break;
9691972b6d9SSteen Hegelund }
9701972b6d9SSteen Hegelund }
9711972b6d9SSteen Hegelund mutex_unlock(&admin->lock);
9721972b6d9SSteen Hegelund if (id)
9731972b6d9SSteen Hegelund return id;
9741972b6d9SSteen Hegelund }
975c9da1ac1SSteen Hegelund return -ENOENT;
976c9da1ac1SSteen Hegelund }
977c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_lookup_rule_by_cookie);
978c9da1ac1SSteen Hegelund
979bfcb94aaSSteen Hegelund /* Get number of rules in a vcap instance lookup chain id range */
vcap_admin_rule_count(struct vcap_admin * admin,int cid)980bfcb94aaSSteen Hegelund int vcap_admin_rule_count(struct vcap_admin *admin, int cid)
981bfcb94aaSSteen Hegelund {
982bfcb94aaSSteen Hegelund int max_cid = roundup(cid + 1, VCAP_CID_LOOKUP_SIZE);
983bfcb94aaSSteen Hegelund int min_cid = rounddown(cid, VCAP_CID_LOOKUP_SIZE);
984bfcb94aaSSteen Hegelund struct vcap_rule_internal *elem;
985bfcb94aaSSteen Hegelund int count = 0;
986bfcb94aaSSteen Hegelund
987bfcb94aaSSteen Hegelund list_for_each_entry(elem, &admin->rules, list) {
988bfcb94aaSSteen Hegelund mutex_lock(&admin->lock);
989bfcb94aaSSteen Hegelund if (elem->data.vcap_chain_id >= min_cid &&
990bfcb94aaSSteen Hegelund elem->data.vcap_chain_id < max_cid)
991bfcb94aaSSteen Hegelund ++count;
992bfcb94aaSSteen Hegelund mutex_unlock(&admin->lock);
993bfcb94aaSSteen Hegelund }
994bfcb94aaSSteen Hegelund return count;
995bfcb94aaSSteen Hegelund }
996bfcb94aaSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_admin_rule_count);
997bfcb94aaSSteen Hegelund
998814e7693SSteen Hegelund /* Make a copy of the rule, shallow or full */
vcap_dup_rule(struct vcap_rule_internal * ri,bool full)999814e7693SSteen Hegelund static struct vcap_rule_internal *vcap_dup_rule(struct vcap_rule_internal *ri,
1000814e7693SSteen Hegelund bool full)
10018e10490bSSteen Hegelund {
1002814e7693SSteen Hegelund struct vcap_client_actionfield *caf, *newcaf;
1003814e7693SSteen Hegelund struct vcap_client_keyfield *ckf, *newckf;
10048e10490bSSteen Hegelund struct vcap_rule_internal *duprule;
10058e10490bSSteen Hegelund
10068e10490bSSteen Hegelund /* Allocate the client part */
10078e10490bSSteen Hegelund duprule = kzalloc(sizeof(*duprule), GFP_KERNEL);
10088e10490bSSteen Hegelund if (!duprule)
10098e10490bSSteen Hegelund return ERR_PTR(-ENOMEM);
10108e10490bSSteen Hegelund *duprule = *ri;
10118e10490bSSteen Hegelund /* Not inserted in the VCAP */
10128e10490bSSteen Hegelund INIT_LIST_HEAD(&duprule->list);
10138e10490bSSteen Hegelund /* No elements in these lists */
10148e10490bSSteen Hegelund INIT_LIST_HEAD(&duprule->data.keyfields);
10158e10490bSSteen Hegelund INIT_LIST_HEAD(&duprule->data.actionfields);
1016814e7693SSteen Hegelund
1017814e7693SSteen Hegelund /* A full rule copy includes keys and actions */
1018814e7693SSteen Hegelund if (!full)
1019814e7693SSteen Hegelund return duprule;
1020814e7693SSteen Hegelund
1021814e7693SSteen Hegelund list_for_each_entry(ckf, &ri->data.keyfields, ctrl.list) {
10225e64f59aSYang Yingliang newckf = kmemdup(ckf, sizeof(*newckf), GFP_KERNEL);
1023814e7693SSteen Hegelund if (!newckf)
1024281f65d2SJinjie Ruan goto err;
1025814e7693SSteen Hegelund list_add_tail(&newckf->ctrl.list, &duprule->data.keyfields);
1026814e7693SSteen Hegelund }
1027814e7693SSteen Hegelund
1028814e7693SSteen Hegelund list_for_each_entry(caf, &ri->data.actionfields, ctrl.list) {
10295e64f59aSYang Yingliang newcaf = kmemdup(caf, sizeof(*newcaf), GFP_KERNEL);
1030814e7693SSteen Hegelund if (!newcaf)
1031281f65d2SJinjie Ruan goto err;
1032814e7693SSteen Hegelund list_add_tail(&newcaf->ctrl.list, &duprule->data.actionfields);
1033814e7693SSteen Hegelund }
1034814e7693SSteen Hegelund
10358e10490bSSteen Hegelund return duprule;
1036281f65d2SJinjie Ruan
1037281f65d2SJinjie Ruan err:
1038281f65d2SJinjie Ruan list_for_each_entry_safe(ckf, newckf, &duprule->data.keyfields, ctrl.list) {
1039281f65d2SJinjie Ruan list_del(&ckf->ctrl.list);
1040281f65d2SJinjie Ruan kfree(ckf);
1041281f65d2SJinjie Ruan }
1042281f65d2SJinjie Ruan
1043281f65d2SJinjie Ruan list_for_each_entry_safe(caf, newcaf, &duprule->data.actionfields, ctrl.list) {
1044281f65d2SJinjie Ruan list_del(&caf->ctrl.list);
1045281f65d2SJinjie Ruan kfree(caf);
1046281f65d2SJinjie Ruan }
1047281f65d2SJinjie Ruan
1048281f65d2SJinjie Ruan kfree(duprule);
1049281f65d2SJinjie Ruan return ERR_PTR(-ENOMEM);
10508e10490bSSteen Hegelund }
10518e10490bSSteen Hegelund
vcap_apply_width(u8 * dst,int width,int bytes)1052610c32b2SHoratiu Vultur static void vcap_apply_width(u8 *dst, int width, int bytes)
1053610c32b2SHoratiu Vultur {
1054610c32b2SHoratiu Vultur u8 bmask;
1055610c32b2SHoratiu Vultur int idx;
1056610c32b2SHoratiu Vultur
1057610c32b2SHoratiu Vultur for (idx = 0; idx < bytes; idx++) {
1058610c32b2SHoratiu Vultur if (width > 0)
1059610c32b2SHoratiu Vultur if (width < 8)
1060610c32b2SHoratiu Vultur bmask = (1 << width) - 1;
1061610c32b2SHoratiu Vultur else
1062610c32b2SHoratiu Vultur bmask = ~0;
1063610c32b2SHoratiu Vultur else
1064610c32b2SHoratiu Vultur bmask = 0;
1065610c32b2SHoratiu Vultur dst[idx] &= bmask;
1066610c32b2SHoratiu Vultur width -= 8;
1067610c32b2SHoratiu Vultur }
1068610c32b2SHoratiu Vultur }
1069610c32b2SHoratiu Vultur
vcap_copy_from_w32be(u8 * dst,u8 * src,int size,int width)1070610c32b2SHoratiu Vultur static void vcap_copy_from_w32be(u8 *dst, u8 *src, int size, int width)
1071610c32b2SHoratiu Vultur {
1072610c32b2SHoratiu Vultur int idx, ridx, wstart, nidx;
1073610c32b2SHoratiu Vultur int tail_bytes = (((size + 4) >> 2) << 2) - size;
1074610c32b2SHoratiu Vultur
1075610c32b2SHoratiu Vultur for (idx = 0, ridx = size - 1; idx < size; ++idx, --ridx) {
1076610c32b2SHoratiu Vultur wstart = (idx >> 2) << 2;
1077610c32b2SHoratiu Vultur nidx = wstart + 3 - (idx & 0x3);
1078610c32b2SHoratiu Vultur if (nidx >= size)
1079610c32b2SHoratiu Vultur nidx -= tail_bytes;
1080610c32b2SHoratiu Vultur dst[nidx] = src[ridx];
1081610c32b2SHoratiu Vultur }
1082610c32b2SHoratiu Vultur
1083610c32b2SHoratiu Vultur vcap_apply_width(dst, width, size);
1084610c32b2SHoratiu Vultur }
1085610c32b2SHoratiu Vultur
vcap_copy_action_bit_field(struct vcap_u1_action * field,u8 * value)1086610c32b2SHoratiu Vultur static void vcap_copy_action_bit_field(struct vcap_u1_action *field, u8 *value)
1087610c32b2SHoratiu Vultur {
1088610c32b2SHoratiu Vultur field->value = (*value) & 0x1;
1089610c32b2SHoratiu Vultur }
1090610c32b2SHoratiu Vultur
vcap_copy_limited_actionfield(u8 * dstvalue,u8 * srcvalue,int width,int bytes)1091610c32b2SHoratiu Vultur static void vcap_copy_limited_actionfield(u8 *dstvalue, u8 *srcvalue,
1092610c32b2SHoratiu Vultur int width, int bytes)
1093610c32b2SHoratiu Vultur {
1094610c32b2SHoratiu Vultur memcpy(dstvalue, srcvalue, bytes);
1095610c32b2SHoratiu Vultur vcap_apply_width(dstvalue, width, bytes);
1096610c32b2SHoratiu Vultur }
1097610c32b2SHoratiu Vultur
vcap_copy_to_client_actionfield(struct vcap_rule_internal * ri,struct vcap_client_actionfield * field,u8 * value,u16 width)1098610c32b2SHoratiu Vultur static void vcap_copy_to_client_actionfield(struct vcap_rule_internal *ri,
1099610c32b2SHoratiu Vultur struct vcap_client_actionfield *field,
1100610c32b2SHoratiu Vultur u8 *value, u16 width)
1101610c32b2SHoratiu Vultur {
1102610c32b2SHoratiu Vultur int field_size = actionfield_size_table[field->ctrl.type];
1103610c32b2SHoratiu Vultur
1104610c32b2SHoratiu Vultur if (ri->admin->w32be) {
1105610c32b2SHoratiu Vultur switch (field->ctrl.type) {
1106610c32b2SHoratiu Vultur case VCAP_FIELD_BIT:
1107610c32b2SHoratiu Vultur vcap_copy_action_bit_field(&field->data.u1, value);
1108610c32b2SHoratiu Vultur break;
1109610c32b2SHoratiu Vultur case VCAP_FIELD_U32:
1110610c32b2SHoratiu Vultur vcap_copy_limited_actionfield((u8 *)&field->data.u32.value,
1111610c32b2SHoratiu Vultur value,
1112610c32b2SHoratiu Vultur width, field_size);
1113610c32b2SHoratiu Vultur break;
1114610c32b2SHoratiu Vultur case VCAP_FIELD_U48:
1115610c32b2SHoratiu Vultur vcap_copy_from_w32be(field->data.u48.value, value,
1116610c32b2SHoratiu Vultur field_size, width);
1117610c32b2SHoratiu Vultur break;
1118610c32b2SHoratiu Vultur case VCAP_FIELD_U56:
1119610c32b2SHoratiu Vultur vcap_copy_from_w32be(field->data.u56.value, value,
1120610c32b2SHoratiu Vultur field_size, width);
1121610c32b2SHoratiu Vultur break;
1122610c32b2SHoratiu Vultur case VCAP_FIELD_U64:
1123610c32b2SHoratiu Vultur vcap_copy_from_w32be(field->data.u64.value, value,
1124610c32b2SHoratiu Vultur field_size, width);
1125610c32b2SHoratiu Vultur break;
1126610c32b2SHoratiu Vultur case VCAP_FIELD_U72:
1127610c32b2SHoratiu Vultur vcap_copy_from_w32be(field->data.u72.value, value,
1128610c32b2SHoratiu Vultur field_size, width);
1129610c32b2SHoratiu Vultur break;
1130610c32b2SHoratiu Vultur case VCAP_FIELD_U112:
1131610c32b2SHoratiu Vultur vcap_copy_from_w32be(field->data.u112.value, value,
1132610c32b2SHoratiu Vultur field_size, width);
1133610c32b2SHoratiu Vultur break;
1134610c32b2SHoratiu Vultur case VCAP_FIELD_U128:
1135610c32b2SHoratiu Vultur vcap_copy_from_w32be(field->data.u128.value, value,
1136610c32b2SHoratiu Vultur field_size, width);
1137610c32b2SHoratiu Vultur break;
1138c515a444SAnup Sharma }
1139610c32b2SHoratiu Vultur } else {
1140610c32b2SHoratiu Vultur switch (field->ctrl.type) {
1141610c32b2SHoratiu Vultur case VCAP_FIELD_BIT:
1142610c32b2SHoratiu Vultur vcap_copy_action_bit_field(&field->data.u1, value);
1143610c32b2SHoratiu Vultur break;
1144610c32b2SHoratiu Vultur case VCAP_FIELD_U32:
1145610c32b2SHoratiu Vultur vcap_copy_limited_actionfield((u8 *)&field->data.u32.value,
1146610c32b2SHoratiu Vultur value,
1147610c32b2SHoratiu Vultur width, field_size);
1148610c32b2SHoratiu Vultur break;
1149610c32b2SHoratiu Vultur case VCAP_FIELD_U48:
1150610c32b2SHoratiu Vultur vcap_copy_limited_actionfield(field->data.u48.value,
1151610c32b2SHoratiu Vultur value,
1152610c32b2SHoratiu Vultur width, field_size);
1153610c32b2SHoratiu Vultur break;
1154610c32b2SHoratiu Vultur case VCAP_FIELD_U56:
1155610c32b2SHoratiu Vultur vcap_copy_limited_actionfield(field->data.u56.value,
1156610c32b2SHoratiu Vultur value,
1157610c32b2SHoratiu Vultur width, field_size);
1158610c32b2SHoratiu Vultur break;
1159610c32b2SHoratiu Vultur case VCAP_FIELD_U64:
1160610c32b2SHoratiu Vultur vcap_copy_limited_actionfield(field->data.u64.value,
1161610c32b2SHoratiu Vultur value,
1162610c32b2SHoratiu Vultur width, field_size);
1163610c32b2SHoratiu Vultur break;
1164610c32b2SHoratiu Vultur case VCAP_FIELD_U72:
1165610c32b2SHoratiu Vultur vcap_copy_limited_actionfield(field->data.u72.value,
1166610c32b2SHoratiu Vultur value,
1167610c32b2SHoratiu Vultur width, field_size);
1168610c32b2SHoratiu Vultur break;
1169610c32b2SHoratiu Vultur case VCAP_FIELD_U112:
1170610c32b2SHoratiu Vultur vcap_copy_limited_actionfield(field->data.u112.value,
1171610c32b2SHoratiu Vultur value,
1172610c32b2SHoratiu Vultur width, field_size);
1173610c32b2SHoratiu Vultur break;
1174610c32b2SHoratiu Vultur case VCAP_FIELD_U128:
1175610c32b2SHoratiu Vultur vcap_copy_limited_actionfield(field->data.u128.value,
1176610c32b2SHoratiu Vultur value,
1177610c32b2SHoratiu Vultur width, field_size);
1178610c32b2SHoratiu Vultur break;
1179c515a444SAnup Sharma }
1180610c32b2SHoratiu Vultur }
1181610c32b2SHoratiu Vultur }
1182610c32b2SHoratiu Vultur
vcap_copy_key_bit_field(struct vcap_u1_key * field,u8 * value,u8 * mask)1183610c32b2SHoratiu Vultur static void vcap_copy_key_bit_field(struct vcap_u1_key *field,
1184610c32b2SHoratiu Vultur u8 *value, u8 *mask)
1185610c32b2SHoratiu Vultur {
1186610c32b2SHoratiu Vultur field->value = (*value) & 0x1;
1187610c32b2SHoratiu Vultur field->mask = (*mask) & 0x1;
1188610c32b2SHoratiu Vultur }
1189610c32b2SHoratiu Vultur
vcap_copy_limited_keyfield(u8 * dstvalue,u8 * dstmask,u8 * srcvalue,u8 * srcmask,int width,int bytes)1190610c32b2SHoratiu Vultur static void vcap_copy_limited_keyfield(u8 *dstvalue, u8 *dstmask,
1191610c32b2SHoratiu Vultur u8 *srcvalue, u8 *srcmask,
1192610c32b2SHoratiu Vultur int width, int bytes)
1193610c32b2SHoratiu Vultur {
1194610c32b2SHoratiu Vultur memcpy(dstvalue, srcvalue, bytes);
1195610c32b2SHoratiu Vultur vcap_apply_width(dstvalue, width, bytes);
1196610c32b2SHoratiu Vultur memcpy(dstmask, srcmask, bytes);
1197610c32b2SHoratiu Vultur vcap_apply_width(dstmask, width, bytes);
1198610c32b2SHoratiu Vultur }
1199610c32b2SHoratiu Vultur
vcap_copy_to_client_keyfield(struct vcap_rule_internal * ri,struct vcap_client_keyfield * field,u8 * value,u8 * mask,u16 width)1200610c32b2SHoratiu Vultur static void vcap_copy_to_client_keyfield(struct vcap_rule_internal *ri,
1201610c32b2SHoratiu Vultur struct vcap_client_keyfield *field,
1202610c32b2SHoratiu Vultur u8 *value, u8 *mask, u16 width)
1203610c32b2SHoratiu Vultur {
1204610c32b2SHoratiu Vultur int field_size = keyfield_size_table[field->ctrl.type] / 2;
1205610c32b2SHoratiu Vultur
1206610c32b2SHoratiu Vultur if (ri->admin->w32be) {
1207610c32b2SHoratiu Vultur switch (field->ctrl.type) {
1208610c32b2SHoratiu Vultur case VCAP_FIELD_BIT:
1209610c32b2SHoratiu Vultur vcap_copy_key_bit_field(&field->data.u1, value, mask);
1210610c32b2SHoratiu Vultur break;
1211610c32b2SHoratiu Vultur case VCAP_FIELD_U32:
1212610c32b2SHoratiu Vultur vcap_copy_limited_keyfield((u8 *)&field->data.u32.value,
1213610c32b2SHoratiu Vultur (u8 *)&field->data.u32.mask,
1214610c32b2SHoratiu Vultur value, mask,
1215610c32b2SHoratiu Vultur width, field_size);
1216610c32b2SHoratiu Vultur break;
1217610c32b2SHoratiu Vultur case VCAP_FIELD_U48:
1218610c32b2SHoratiu Vultur vcap_copy_from_w32be(field->data.u48.value, value,
1219610c32b2SHoratiu Vultur field_size, width);
1220610c32b2SHoratiu Vultur vcap_copy_from_w32be(field->data.u48.mask, mask,
1221610c32b2SHoratiu Vultur field_size, width);
1222610c32b2SHoratiu Vultur break;
1223610c32b2SHoratiu Vultur case VCAP_FIELD_U56:
1224610c32b2SHoratiu Vultur vcap_copy_from_w32be(field->data.u56.value, value,
1225610c32b2SHoratiu Vultur field_size, width);
1226610c32b2SHoratiu Vultur vcap_copy_from_w32be(field->data.u56.mask, mask,
1227610c32b2SHoratiu Vultur field_size, width);
1228610c32b2SHoratiu Vultur break;
1229610c32b2SHoratiu Vultur case VCAP_FIELD_U64:
1230610c32b2SHoratiu Vultur vcap_copy_from_w32be(field->data.u64.value, value,
1231610c32b2SHoratiu Vultur field_size, width);
1232610c32b2SHoratiu Vultur vcap_copy_from_w32be(field->data.u64.mask, mask,
1233610c32b2SHoratiu Vultur field_size, width);
1234610c32b2SHoratiu Vultur break;
1235610c32b2SHoratiu Vultur case VCAP_FIELD_U72:
1236610c32b2SHoratiu Vultur vcap_copy_from_w32be(field->data.u72.value, value,
1237610c32b2SHoratiu Vultur field_size, width);
1238610c32b2SHoratiu Vultur vcap_copy_from_w32be(field->data.u72.mask, mask,
1239610c32b2SHoratiu Vultur field_size, width);
1240610c32b2SHoratiu Vultur break;
1241610c32b2SHoratiu Vultur case VCAP_FIELD_U112:
1242610c32b2SHoratiu Vultur vcap_copy_from_w32be(field->data.u112.value, value,
1243610c32b2SHoratiu Vultur field_size, width);
1244610c32b2SHoratiu Vultur vcap_copy_from_w32be(field->data.u112.mask, mask,
1245610c32b2SHoratiu Vultur field_size, width);
1246610c32b2SHoratiu Vultur break;
1247610c32b2SHoratiu Vultur case VCAP_FIELD_U128:
1248610c32b2SHoratiu Vultur vcap_copy_from_w32be(field->data.u128.value, value,
1249610c32b2SHoratiu Vultur field_size, width);
1250610c32b2SHoratiu Vultur vcap_copy_from_w32be(field->data.u128.mask, mask,
1251610c32b2SHoratiu Vultur field_size, width);
1252610c32b2SHoratiu Vultur break;
1253c515a444SAnup Sharma }
1254610c32b2SHoratiu Vultur } else {
1255610c32b2SHoratiu Vultur switch (field->ctrl.type) {
1256610c32b2SHoratiu Vultur case VCAP_FIELD_BIT:
1257610c32b2SHoratiu Vultur vcap_copy_key_bit_field(&field->data.u1, value, mask);
1258610c32b2SHoratiu Vultur break;
1259610c32b2SHoratiu Vultur case VCAP_FIELD_U32:
1260610c32b2SHoratiu Vultur vcap_copy_limited_keyfield((u8 *)&field->data.u32.value,
1261610c32b2SHoratiu Vultur (u8 *)&field->data.u32.mask,
1262610c32b2SHoratiu Vultur value, mask,
1263610c32b2SHoratiu Vultur width, field_size);
1264610c32b2SHoratiu Vultur break;
1265610c32b2SHoratiu Vultur case VCAP_FIELD_U48:
1266610c32b2SHoratiu Vultur vcap_copy_limited_keyfield(field->data.u48.value,
1267610c32b2SHoratiu Vultur field->data.u48.mask,
1268610c32b2SHoratiu Vultur value, mask,
1269610c32b2SHoratiu Vultur width, field_size);
1270610c32b2SHoratiu Vultur break;
1271610c32b2SHoratiu Vultur case VCAP_FIELD_U56:
1272610c32b2SHoratiu Vultur vcap_copy_limited_keyfield(field->data.u56.value,
1273610c32b2SHoratiu Vultur field->data.u56.mask,
1274610c32b2SHoratiu Vultur value, mask,
1275610c32b2SHoratiu Vultur width, field_size);
1276610c32b2SHoratiu Vultur break;
1277610c32b2SHoratiu Vultur case VCAP_FIELD_U64:
1278610c32b2SHoratiu Vultur vcap_copy_limited_keyfield(field->data.u64.value,
1279610c32b2SHoratiu Vultur field->data.u64.mask,
1280610c32b2SHoratiu Vultur value, mask,
1281610c32b2SHoratiu Vultur width, field_size);
1282610c32b2SHoratiu Vultur break;
1283610c32b2SHoratiu Vultur case VCAP_FIELD_U72:
1284610c32b2SHoratiu Vultur vcap_copy_limited_keyfield(field->data.u72.value,
1285610c32b2SHoratiu Vultur field->data.u72.mask,
1286610c32b2SHoratiu Vultur value, mask,
1287610c32b2SHoratiu Vultur width, field_size);
1288610c32b2SHoratiu Vultur break;
1289610c32b2SHoratiu Vultur case VCAP_FIELD_U112:
1290610c32b2SHoratiu Vultur vcap_copy_limited_keyfield(field->data.u112.value,
1291610c32b2SHoratiu Vultur field->data.u112.mask,
1292610c32b2SHoratiu Vultur value, mask,
1293610c32b2SHoratiu Vultur width, field_size);
1294610c32b2SHoratiu Vultur break;
1295610c32b2SHoratiu Vultur case VCAP_FIELD_U128:
1296610c32b2SHoratiu Vultur vcap_copy_limited_keyfield(field->data.u128.value,
1297610c32b2SHoratiu Vultur field->data.u128.mask,
1298610c32b2SHoratiu Vultur value, mask,
1299610c32b2SHoratiu Vultur width, field_size);
1300610c32b2SHoratiu Vultur break;
1301c515a444SAnup Sharma }
1302610c32b2SHoratiu Vultur }
1303610c32b2SHoratiu Vultur }
1304610c32b2SHoratiu Vultur
vcap_rule_alloc_keyfield(struct vcap_rule_internal * ri,const struct vcap_field * keyfield,enum vcap_key_field key,u8 * value,u8 * mask)1305610c32b2SHoratiu Vultur static void vcap_rule_alloc_keyfield(struct vcap_rule_internal *ri,
1306610c32b2SHoratiu Vultur const struct vcap_field *keyfield,
1307610c32b2SHoratiu Vultur enum vcap_key_field key,
1308610c32b2SHoratiu Vultur u8 *value, u8 *mask)
1309610c32b2SHoratiu Vultur {
1310610c32b2SHoratiu Vultur struct vcap_client_keyfield *field;
1311610c32b2SHoratiu Vultur
1312610c32b2SHoratiu Vultur field = kzalloc(sizeof(*field), GFP_KERNEL);
1313610c32b2SHoratiu Vultur if (!field)
1314610c32b2SHoratiu Vultur return;
1315610c32b2SHoratiu Vultur INIT_LIST_HEAD(&field->ctrl.list);
1316610c32b2SHoratiu Vultur field->ctrl.key = key;
1317610c32b2SHoratiu Vultur field->ctrl.type = keyfield->type;
1318610c32b2SHoratiu Vultur vcap_copy_to_client_keyfield(ri, field, value, mask, keyfield->width);
1319610c32b2SHoratiu Vultur list_add_tail(&field->ctrl.list, &ri->data.keyfields);
1320610c32b2SHoratiu Vultur }
1321610c32b2SHoratiu Vultur
1322610c32b2SHoratiu Vultur /* Read key data from a VCAP address and discover if there is a rule keyset
1323610c32b2SHoratiu Vultur * here
1324610c32b2SHoratiu Vultur */
1325610c32b2SHoratiu Vultur static bool
vcap_verify_actionstream_actionset(struct vcap_control * vctrl,enum vcap_type vt,u32 * actionstream,enum vcap_actionfield_set actionset)1326610c32b2SHoratiu Vultur vcap_verify_actionstream_actionset(struct vcap_control *vctrl,
1327610c32b2SHoratiu Vultur enum vcap_type vt,
1328610c32b2SHoratiu Vultur u32 *actionstream,
1329610c32b2SHoratiu Vultur enum vcap_actionfield_set actionset)
1330610c32b2SHoratiu Vultur {
1331610c32b2SHoratiu Vultur const struct vcap_typegroup *tgt;
1332610c32b2SHoratiu Vultur const struct vcap_field *fields;
1333610c32b2SHoratiu Vultur const struct vcap_set *info;
1334610c32b2SHoratiu Vultur
1335610c32b2SHoratiu Vultur if (vcap_actionfield_count(vctrl, vt, actionset) == 0)
1336610c32b2SHoratiu Vultur return false;
1337610c32b2SHoratiu Vultur
1338610c32b2SHoratiu Vultur info = vcap_actionfieldset(vctrl, vt, actionset);
1339610c32b2SHoratiu Vultur /* Check that the actionset is valid */
1340610c32b2SHoratiu Vultur if (!info)
1341610c32b2SHoratiu Vultur return false;
1342610c32b2SHoratiu Vultur
1343610c32b2SHoratiu Vultur /* a type_id of value -1 means that there is no type field */
1344610c32b2SHoratiu Vultur if (info->type_id == (u8)-1)
1345610c32b2SHoratiu Vultur return true;
1346610c32b2SHoratiu Vultur
1347610c32b2SHoratiu Vultur /* Get a valid typegroup for the specific actionset */
1348610c32b2SHoratiu Vultur tgt = vcap_actionfield_typegroup(vctrl, vt, actionset);
1349610c32b2SHoratiu Vultur if (!tgt)
1350610c32b2SHoratiu Vultur return false;
1351610c32b2SHoratiu Vultur
1352610c32b2SHoratiu Vultur fields = vcap_actionfields(vctrl, vt, actionset);
1353610c32b2SHoratiu Vultur if (!fields)
1354610c32b2SHoratiu Vultur return false;
1355610c32b2SHoratiu Vultur
1356610c32b2SHoratiu Vultur /* Later this will be expanded with a check of the type id */
1357610c32b2SHoratiu Vultur return true;
1358610c32b2SHoratiu Vultur }
1359610c32b2SHoratiu Vultur
1360610c32b2SHoratiu Vultur /* Find the subword width of the action typegroup that matches the stream data
1361610c32b2SHoratiu Vultur */
vcap_find_actionstream_typegroup_sw(struct vcap_control * vctrl,enum vcap_type vt,u32 * stream,int sw_max)1362610c32b2SHoratiu Vultur static int vcap_find_actionstream_typegroup_sw(struct vcap_control *vctrl,
1363610c32b2SHoratiu Vultur enum vcap_type vt, u32 *stream,
1364610c32b2SHoratiu Vultur int sw_max)
1365610c32b2SHoratiu Vultur {
1366610c32b2SHoratiu Vultur const struct vcap_typegroup **tgt;
1367610c32b2SHoratiu Vultur int sw_idx, res;
1368610c32b2SHoratiu Vultur
1369610c32b2SHoratiu Vultur tgt = vctrl->vcaps[vt].actionfield_set_typegroups;
1370610c32b2SHoratiu Vultur /* Try the longest subword match first */
1371610c32b2SHoratiu Vultur for (sw_idx = vctrl->vcaps[vt].sw_count; sw_idx >= 0; sw_idx--) {
1372610c32b2SHoratiu Vultur if (!tgt[sw_idx])
1373610c32b2SHoratiu Vultur continue;
1374610c32b2SHoratiu Vultur res = vcap_verify_typegroups(stream, vctrl->vcaps[vt].act_width,
1375610c32b2SHoratiu Vultur tgt[sw_idx], false, sw_max);
1376610c32b2SHoratiu Vultur if (res == 0)
1377610c32b2SHoratiu Vultur return sw_idx;
1378610c32b2SHoratiu Vultur }
1379610c32b2SHoratiu Vultur return -EINVAL;
1380610c32b2SHoratiu Vultur }
1381610c32b2SHoratiu Vultur
1382610c32b2SHoratiu Vultur /* Verify that the typegroup information, subword count, actionset and type id
1383610c32b2SHoratiu Vultur * are in sync and correct, return the actionset
1384610c32b2SHoratiu Vultur */
1385610c32b2SHoratiu Vultur static enum vcap_actionfield_set
vcap_find_actionstream_actionset(struct vcap_control * vctrl,enum vcap_type vt,u32 * stream,int sw_max)1386610c32b2SHoratiu Vultur vcap_find_actionstream_actionset(struct vcap_control *vctrl,
1387610c32b2SHoratiu Vultur enum vcap_type vt,
1388610c32b2SHoratiu Vultur u32 *stream,
1389610c32b2SHoratiu Vultur int sw_max)
1390610c32b2SHoratiu Vultur {
1391610c32b2SHoratiu Vultur const struct vcap_set *actionfield_set;
1392610c32b2SHoratiu Vultur int sw_count, idx;
1393610c32b2SHoratiu Vultur bool res;
1394610c32b2SHoratiu Vultur
1395610c32b2SHoratiu Vultur sw_count = vcap_find_actionstream_typegroup_sw(vctrl, vt, stream,
1396610c32b2SHoratiu Vultur sw_max);
1397610c32b2SHoratiu Vultur if (sw_count < 0)
1398610c32b2SHoratiu Vultur return sw_count;
1399610c32b2SHoratiu Vultur
1400610c32b2SHoratiu Vultur actionfield_set = vctrl->vcaps[vt].actionfield_set;
1401610c32b2SHoratiu Vultur for (idx = 0; idx < vctrl->vcaps[vt].actionfield_set_size; ++idx) {
1402610c32b2SHoratiu Vultur if (actionfield_set[idx].sw_per_item != sw_count)
1403610c32b2SHoratiu Vultur continue;
1404610c32b2SHoratiu Vultur
1405610c32b2SHoratiu Vultur res = vcap_verify_actionstream_actionset(vctrl, vt,
1406610c32b2SHoratiu Vultur stream, idx);
1407610c32b2SHoratiu Vultur if (res)
1408610c32b2SHoratiu Vultur return idx;
1409610c32b2SHoratiu Vultur }
1410610c32b2SHoratiu Vultur return -EINVAL;
1411610c32b2SHoratiu Vultur }
1412610c32b2SHoratiu Vultur
1413610c32b2SHoratiu Vultur /* Store action value in an element in a list for the client */
vcap_rule_alloc_actionfield(struct vcap_rule_internal * ri,const struct vcap_field * actionfield,enum vcap_action_field action,u8 * value)1414610c32b2SHoratiu Vultur static void vcap_rule_alloc_actionfield(struct vcap_rule_internal *ri,
1415610c32b2SHoratiu Vultur const struct vcap_field *actionfield,
1416610c32b2SHoratiu Vultur enum vcap_action_field action,
1417610c32b2SHoratiu Vultur u8 *value)
1418610c32b2SHoratiu Vultur {
1419610c32b2SHoratiu Vultur struct vcap_client_actionfield *field;
1420610c32b2SHoratiu Vultur
1421610c32b2SHoratiu Vultur field = kzalloc(sizeof(*field), GFP_KERNEL);
1422610c32b2SHoratiu Vultur if (!field)
1423610c32b2SHoratiu Vultur return;
1424610c32b2SHoratiu Vultur INIT_LIST_HEAD(&field->ctrl.list);
1425610c32b2SHoratiu Vultur field->ctrl.action = action;
1426610c32b2SHoratiu Vultur field->ctrl.type = actionfield->type;
1427610c32b2SHoratiu Vultur vcap_copy_to_client_actionfield(ri, field, value, actionfield->width);
1428610c32b2SHoratiu Vultur list_add_tail(&field->ctrl.list, &ri->data.actionfields);
1429610c32b2SHoratiu Vultur }
1430610c32b2SHoratiu Vultur
vcap_decode_actionset(struct vcap_rule_internal * ri)1431610c32b2SHoratiu Vultur static int vcap_decode_actionset(struct vcap_rule_internal *ri)
1432610c32b2SHoratiu Vultur {
1433610c32b2SHoratiu Vultur struct vcap_control *vctrl = ri->vctrl;
1434610c32b2SHoratiu Vultur struct vcap_admin *admin = ri->admin;
1435610c32b2SHoratiu Vultur const struct vcap_field *actionfield;
1436610c32b2SHoratiu Vultur enum vcap_actionfield_set actionset;
1437610c32b2SHoratiu Vultur enum vcap_type vt = admin->vtype;
1438610c32b2SHoratiu Vultur const struct vcap_typegroup *tgt;
1439610c32b2SHoratiu Vultur struct vcap_stream_iter iter;
1440610c32b2SHoratiu Vultur int idx, res, actfield_count;
1441610c32b2SHoratiu Vultur u32 *actstream;
1442610c32b2SHoratiu Vultur u8 value[16];
1443610c32b2SHoratiu Vultur
1444610c32b2SHoratiu Vultur actstream = admin->cache.actionstream;
1445610c32b2SHoratiu Vultur res = vcap_find_actionstream_actionset(vctrl, vt, actstream, 0);
1446610c32b2SHoratiu Vultur if (res < 0) {
1447610c32b2SHoratiu Vultur pr_err("%s:%d: could not find valid actionset: %d\n",
1448610c32b2SHoratiu Vultur __func__, __LINE__, res);
1449610c32b2SHoratiu Vultur return -EINVAL;
1450610c32b2SHoratiu Vultur }
1451610c32b2SHoratiu Vultur actionset = res;
1452610c32b2SHoratiu Vultur actfield_count = vcap_actionfield_count(vctrl, vt, actionset);
1453610c32b2SHoratiu Vultur actionfield = vcap_actionfields(vctrl, vt, actionset);
1454610c32b2SHoratiu Vultur tgt = vcap_actionfield_typegroup(vctrl, vt, actionset);
1455610c32b2SHoratiu Vultur /* Start decoding the stream */
1456610c32b2SHoratiu Vultur for (idx = 0; idx < actfield_count; ++idx) {
1457610c32b2SHoratiu Vultur if (actionfield[idx].width <= 0)
1458610c32b2SHoratiu Vultur continue;
1459610c32b2SHoratiu Vultur /* Get the action */
1460610c32b2SHoratiu Vultur memset(value, 0, DIV_ROUND_UP(actionfield[idx].width, 8));
1461610c32b2SHoratiu Vultur vcap_iter_init(&iter, vctrl->vcaps[vt].act_width, tgt,
1462610c32b2SHoratiu Vultur actionfield[idx].offset);
1463610c32b2SHoratiu Vultur vcap_decode_field(actstream, &iter, actionfield[idx].width,
1464610c32b2SHoratiu Vultur value);
1465610c32b2SHoratiu Vultur /* Skip if no bits are set */
1466610c32b2SHoratiu Vultur if (vcap_bitarray_zero(actionfield[idx].width, value))
1467610c32b2SHoratiu Vultur continue;
1468610c32b2SHoratiu Vultur vcap_rule_alloc_actionfield(ri, &actionfield[idx], idx, value);
1469610c32b2SHoratiu Vultur /* Later the action id will also be checked */
1470610c32b2SHoratiu Vultur }
1471610c32b2SHoratiu Vultur return vcap_set_rule_set_actionset((struct vcap_rule *)ri, actionset);
1472610c32b2SHoratiu Vultur }
1473610c32b2SHoratiu Vultur
vcap_decode_keyset(struct vcap_rule_internal * ri)1474610c32b2SHoratiu Vultur static int vcap_decode_keyset(struct vcap_rule_internal *ri)
1475610c32b2SHoratiu Vultur {
1476610c32b2SHoratiu Vultur struct vcap_control *vctrl = ri->vctrl;
1477610c32b2SHoratiu Vultur struct vcap_stream_iter kiter, miter;
1478610c32b2SHoratiu Vultur struct vcap_admin *admin = ri->admin;
1479610c32b2SHoratiu Vultur enum vcap_keyfield_set keysets[10];
1480610c32b2SHoratiu Vultur const struct vcap_field *keyfield;
1481610c32b2SHoratiu Vultur enum vcap_type vt = admin->vtype;
1482610c32b2SHoratiu Vultur const struct vcap_typegroup *tgt;
1483610c32b2SHoratiu Vultur struct vcap_keyset_list matches;
1484610c32b2SHoratiu Vultur enum vcap_keyfield_set keyset;
1485610c32b2SHoratiu Vultur int idx, res, keyfield_count;
1486610c32b2SHoratiu Vultur u32 *maskstream;
1487610c32b2SHoratiu Vultur u32 *keystream;
1488610c32b2SHoratiu Vultur u8 value[16];
1489610c32b2SHoratiu Vultur u8 mask[16];
1490610c32b2SHoratiu Vultur
1491610c32b2SHoratiu Vultur keystream = admin->cache.keystream;
1492610c32b2SHoratiu Vultur maskstream = admin->cache.maskstream;
1493610c32b2SHoratiu Vultur matches.keysets = keysets;
1494610c32b2SHoratiu Vultur matches.cnt = 0;
1495610c32b2SHoratiu Vultur matches.max = ARRAY_SIZE(keysets);
1496610c32b2SHoratiu Vultur res = vcap_find_keystream_keysets(vctrl, vt, keystream, maskstream,
1497610c32b2SHoratiu Vultur false, 0, &matches);
1498610c32b2SHoratiu Vultur if (res < 0) {
1499610c32b2SHoratiu Vultur pr_err("%s:%d: could not find valid keysets: %d\n",
1500610c32b2SHoratiu Vultur __func__, __LINE__, res);
1501610c32b2SHoratiu Vultur return -EINVAL;
1502610c32b2SHoratiu Vultur }
1503610c32b2SHoratiu Vultur keyset = matches.keysets[0];
1504610c32b2SHoratiu Vultur keyfield_count = vcap_keyfield_count(vctrl, vt, keyset);
1505610c32b2SHoratiu Vultur keyfield = vcap_keyfields(vctrl, vt, keyset);
1506610c32b2SHoratiu Vultur tgt = vcap_keyfield_typegroup(vctrl, vt, keyset);
1507610c32b2SHoratiu Vultur /* Start decoding the streams */
1508610c32b2SHoratiu Vultur for (idx = 0; idx < keyfield_count; ++idx) {
1509610c32b2SHoratiu Vultur if (keyfield[idx].width <= 0)
1510610c32b2SHoratiu Vultur continue;
1511610c32b2SHoratiu Vultur /* First get the mask */
1512610c32b2SHoratiu Vultur memset(mask, 0, DIV_ROUND_UP(keyfield[idx].width, 8));
1513610c32b2SHoratiu Vultur vcap_iter_init(&miter, vctrl->vcaps[vt].sw_width, tgt,
1514610c32b2SHoratiu Vultur keyfield[idx].offset);
1515610c32b2SHoratiu Vultur vcap_decode_field(maskstream, &miter, keyfield[idx].width,
1516610c32b2SHoratiu Vultur mask);
1517610c32b2SHoratiu Vultur /* Skip if no mask bits are set */
1518610c32b2SHoratiu Vultur if (vcap_bitarray_zero(keyfield[idx].width, mask))
1519610c32b2SHoratiu Vultur continue;
1520610c32b2SHoratiu Vultur /* Get the key */
1521610c32b2SHoratiu Vultur memset(value, 0, DIV_ROUND_UP(keyfield[idx].width, 8));
1522610c32b2SHoratiu Vultur vcap_iter_init(&kiter, vctrl->vcaps[vt].sw_width, tgt,
1523610c32b2SHoratiu Vultur keyfield[idx].offset);
1524610c32b2SHoratiu Vultur vcap_decode_field(keystream, &kiter, keyfield[idx].width,
1525610c32b2SHoratiu Vultur value);
1526610c32b2SHoratiu Vultur vcap_rule_alloc_keyfield(ri, &keyfield[idx], idx, value, mask);
1527610c32b2SHoratiu Vultur }
1528610c32b2SHoratiu Vultur return vcap_set_rule_set_keyset((struct vcap_rule *)ri, keyset);
1529610c32b2SHoratiu Vultur }
1530610c32b2SHoratiu Vultur
1531610c32b2SHoratiu Vultur /* Read VCAP content into the VCAP cache */
vcap_read_rule(struct vcap_rule_internal * ri)1532610c32b2SHoratiu Vultur static int vcap_read_rule(struct vcap_rule_internal *ri)
1533610c32b2SHoratiu Vultur {
1534610c32b2SHoratiu Vultur struct vcap_admin *admin = ri->admin;
1535610c32b2SHoratiu Vultur int sw_idx, ent_idx = 0, act_idx = 0;
1536610c32b2SHoratiu Vultur u32 addr = ri->addr;
1537610c32b2SHoratiu Vultur
1538610c32b2SHoratiu Vultur if (!ri->size || !ri->keyset_sw_regs || !ri->actionset_sw_regs) {
1539610c32b2SHoratiu Vultur pr_err("%s:%d: rule is empty\n", __func__, __LINE__);
1540610c32b2SHoratiu Vultur return -EINVAL;
1541610c32b2SHoratiu Vultur }
1542610c32b2SHoratiu Vultur vcap_erase_cache(ri);
1543610c32b2SHoratiu Vultur /* Use the values in the streams to read the VCAP cache */
1544610c32b2SHoratiu Vultur for (sw_idx = 0; sw_idx < ri->size; sw_idx++, addr++) {
1545610c32b2SHoratiu Vultur ri->vctrl->ops->update(ri->ndev, admin, VCAP_CMD_READ,
1546610c32b2SHoratiu Vultur VCAP_SEL_ALL, addr);
1547610c32b2SHoratiu Vultur ri->vctrl->ops->cache_read(ri->ndev, admin,
1548610c32b2SHoratiu Vultur VCAP_SEL_ENTRY, ent_idx,
1549610c32b2SHoratiu Vultur ri->keyset_sw_regs);
1550610c32b2SHoratiu Vultur ri->vctrl->ops->cache_read(ri->ndev, admin,
1551610c32b2SHoratiu Vultur VCAP_SEL_ACTION, act_idx,
1552610c32b2SHoratiu Vultur ri->actionset_sw_regs);
1553610c32b2SHoratiu Vultur if (sw_idx == 0)
1554610c32b2SHoratiu Vultur ri->vctrl->ops->cache_read(ri->ndev, admin,
1555610c32b2SHoratiu Vultur VCAP_SEL_COUNTER,
1556610c32b2SHoratiu Vultur ri->counter_id, 0);
1557610c32b2SHoratiu Vultur ent_idx += ri->keyset_sw_regs;
1558610c32b2SHoratiu Vultur act_idx += ri->actionset_sw_regs;
1559610c32b2SHoratiu Vultur }
1560610c32b2SHoratiu Vultur return 0;
1561610c32b2SHoratiu Vultur }
1562610c32b2SHoratiu Vultur
15638e10490bSSteen Hegelund /* Write VCAP cache content to the VCAP HW instance */
vcap_write_rule(struct vcap_rule_internal * ri)15648e10490bSSteen Hegelund static int vcap_write_rule(struct vcap_rule_internal *ri)
15658e10490bSSteen Hegelund {
15668e10490bSSteen Hegelund struct vcap_admin *admin = ri->admin;
15678e10490bSSteen Hegelund int sw_idx, ent_idx = 0, act_idx = 0;
15688e10490bSSteen Hegelund u32 addr = ri->addr;
15698e10490bSSteen Hegelund
15708e10490bSSteen Hegelund if (!ri->size || !ri->keyset_sw_regs || !ri->actionset_sw_regs) {
15718e10490bSSteen Hegelund pr_err("%s:%d: rule is empty\n", __func__, __LINE__);
15728e10490bSSteen Hegelund return -EINVAL;
15738e10490bSSteen Hegelund }
15748e10490bSSteen Hegelund /* Use the values in the streams to write the VCAP cache */
15758e10490bSSteen Hegelund for (sw_idx = 0; sw_idx < ri->size; sw_idx++, addr++) {
15768e10490bSSteen Hegelund ri->vctrl->ops->cache_write(ri->ndev, admin,
15778e10490bSSteen Hegelund VCAP_SEL_ENTRY, ent_idx,
15788e10490bSSteen Hegelund ri->keyset_sw_regs);
15798e10490bSSteen Hegelund ri->vctrl->ops->cache_write(ri->ndev, admin,
15808e10490bSSteen Hegelund VCAP_SEL_ACTION, act_idx,
15818e10490bSSteen Hegelund ri->actionset_sw_regs);
15828e10490bSSteen Hegelund ri->vctrl->ops->update(ri->ndev, admin, VCAP_CMD_WRITE,
15838e10490bSSteen Hegelund VCAP_SEL_ALL, addr);
15848e10490bSSteen Hegelund ent_idx += ri->keyset_sw_regs;
15858e10490bSSteen Hegelund act_idx += ri->actionset_sw_regs;
15868e10490bSSteen Hegelund }
15878e10490bSSteen Hegelund return 0;
15888e10490bSSteen Hegelund }
15898e10490bSSteen Hegelund
vcap_write_counter(struct vcap_rule_internal * ri,struct vcap_counter * ctr)1590f13230a4SSteen Hegelund static int vcap_write_counter(struct vcap_rule_internal *ri,
1591f13230a4SSteen Hegelund struct vcap_counter *ctr)
1592f13230a4SSteen Hegelund {
1593f13230a4SSteen Hegelund struct vcap_admin *admin = ri->admin;
1594f13230a4SSteen Hegelund
1595f13230a4SSteen Hegelund admin->cache.counter = ctr->value;
1596f13230a4SSteen Hegelund admin->cache.sticky = ctr->sticky;
1597f13230a4SSteen Hegelund ri->vctrl->ops->cache_write(ri->ndev, admin, VCAP_SEL_COUNTER,
1598f13230a4SSteen Hegelund ri->counter_id, 0);
1599f13230a4SSteen Hegelund ri->vctrl->ops->update(ri->ndev, admin, VCAP_CMD_WRITE,
1600f13230a4SSteen Hegelund VCAP_SEL_COUNTER, ri->addr);
1601f13230a4SSteen Hegelund return 0;
1602f13230a4SSteen Hegelund }
1603f13230a4SSteen Hegelund
16047de1dcadSSteen Hegelund /* Convert a chain id to a VCAP lookup index */
vcap_chain_id_to_lookup(struct vcap_admin * admin,int cur_cid)16057de1dcadSSteen Hegelund int vcap_chain_id_to_lookup(struct vcap_admin *admin, int cur_cid)
16067de1dcadSSteen Hegelund {
16077de1dcadSSteen Hegelund int lookup_first = admin->vinst * admin->lookups_per_instance;
16087de1dcadSSteen Hegelund int lookup_last = lookup_first + admin->lookups_per_instance;
16097de1dcadSSteen Hegelund int cid_next = admin->first_cid + VCAP_CID_LOOKUP_SIZE;
16107de1dcadSSteen Hegelund int cid = admin->first_cid;
16117de1dcadSSteen Hegelund int lookup;
16127de1dcadSSteen Hegelund
16137de1dcadSSteen Hegelund for (lookup = lookup_first; lookup < lookup_last; ++lookup,
16147de1dcadSSteen Hegelund cid += VCAP_CID_LOOKUP_SIZE, cid_next += VCAP_CID_LOOKUP_SIZE)
16157de1dcadSSteen Hegelund if (cur_cid >= cid && cur_cid < cid_next)
16167de1dcadSSteen Hegelund return lookup;
16177de1dcadSSteen Hegelund return 0;
16187de1dcadSSteen Hegelund }
16197de1dcadSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_chain_id_to_lookup);
16207de1dcadSSteen Hegelund
1621c9da1ac1SSteen Hegelund /* Lookup a vcap instance using chain id */
vcap_find_admin(struct vcap_control * vctrl,int cid)1622c9da1ac1SSteen Hegelund struct vcap_admin *vcap_find_admin(struct vcap_control *vctrl, int cid)
1623c9da1ac1SSteen Hegelund {
1624c9da1ac1SSteen Hegelund struct vcap_admin *admin;
1625c9da1ac1SSteen Hegelund
16268e10490bSSteen Hegelund if (vcap_api_check(vctrl))
16278e10490bSSteen Hegelund return NULL;
16288e10490bSSteen Hegelund
1629c9da1ac1SSteen Hegelund list_for_each_entry(admin, &vctrl->list, list) {
1630c9da1ac1SSteen Hegelund if (cid >= admin->first_cid && cid <= admin->last_cid)
1631c9da1ac1SSteen Hegelund return admin;
1632c9da1ac1SSteen Hegelund }
1633c9da1ac1SSteen Hegelund return NULL;
1634c9da1ac1SSteen Hegelund }
1635c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_find_admin);
1636c9da1ac1SSteen Hegelund
1637e7e3f514SSteen Hegelund /* Is this the last admin instance ordered by chain id and direction */
vcap_admin_is_last(struct vcap_control * vctrl,struct vcap_admin * admin,bool ingress)163888bd9ea7SSteen Hegelund static bool vcap_admin_is_last(struct vcap_control *vctrl,
1639e7e3f514SSteen Hegelund struct vcap_admin *admin,
1640e7e3f514SSteen Hegelund bool ingress)
164188bd9ea7SSteen Hegelund {
164288bd9ea7SSteen Hegelund struct vcap_admin *iter, *last = NULL;
164388bd9ea7SSteen Hegelund int max_cid = 0;
164488bd9ea7SSteen Hegelund
164588bd9ea7SSteen Hegelund list_for_each_entry(iter, &vctrl->list, list) {
1646e7e3f514SSteen Hegelund if (iter->first_cid > max_cid &&
1647e7e3f514SSteen Hegelund iter->ingress == ingress) {
164888bd9ea7SSteen Hegelund last = iter;
164988bd9ea7SSteen Hegelund max_cid = iter->first_cid;
165088bd9ea7SSteen Hegelund }
165188bd9ea7SSteen Hegelund }
165288bd9ea7SSteen Hegelund if (!last)
165388bd9ea7SSteen Hegelund return false;
165488bd9ea7SSteen Hegelund
165588bd9ea7SSteen Hegelund return admin == last;
165688bd9ea7SSteen Hegelund }
165788bd9ea7SSteen Hegelund
165888bd9ea7SSteen Hegelund /* Calculate the value used for chaining VCAP rules */
vcap_chain_offset(struct vcap_control * vctrl,int from_cid,int to_cid)165988bd9ea7SSteen Hegelund int vcap_chain_offset(struct vcap_control *vctrl, int from_cid, int to_cid)
166088bd9ea7SSteen Hegelund {
166188bd9ea7SSteen Hegelund int diff = to_cid - from_cid;
166288bd9ea7SSteen Hegelund
166388bd9ea7SSteen Hegelund if (diff < 0) /* Wrong direction */
166488bd9ea7SSteen Hegelund return diff;
166588bd9ea7SSteen Hegelund to_cid %= VCAP_CID_LOOKUP_SIZE;
166688bd9ea7SSteen Hegelund if (to_cid == 0) /* Destination aligned to a lookup == no chaining */
166788bd9ea7SSteen Hegelund return 0;
166888bd9ea7SSteen Hegelund diff %= VCAP_CID_LOOKUP_SIZE; /* Limit to a value within a lookup */
166988bd9ea7SSteen Hegelund return diff;
167088bd9ea7SSteen Hegelund }
167188bd9ea7SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_chain_offset);
167288bd9ea7SSteen Hegelund
1673784c3067SSteen Hegelund /* Is the next chain id in one of the following lookups
1674784c3067SSteen Hegelund * For now this does not support filters linked to other filters using
1675784c3067SSteen Hegelund * keys and actions. That will be added later.
1676784c3067SSteen Hegelund */
vcap_is_next_lookup(struct vcap_control * vctrl,int src_cid,int dst_cid)1677784c3067SSteen Hegelund bool vcap_is_next_lookup(struct vcap_control *vctrl, int src_cid, int dst_cid)
1678392d0ab0SSteen Hegelund {
1679784c3067SSteen Hegelund struct vcap_admin *admin;
1680784c3067SSteen Hegelund int next_cid;
1681392d0ab0SSteen Hegelund
1682392d0ab0SSteen Hegelund if (vcap_api_check(vctrl))
1683392d0ab0SSteen Hegelund return false;
1684392d0ab0SSteen Hegelund
16850518e914SSteen Hegelund /* The offset must be at least one lookup so round up one chain */
16860518e914SSteen Hegelund next_cid = roundup(src_cid + 1, VCAP_CID_LOOKUP_SIZE);
1687784c3067SSteen Hegelund
1688784c3067SSteen Hegelund if (dst_cid < next_cid)
1689784c3067SSteen Hegelund return false;
1690784c3067SSteen Hegelund
1691784c3067SSteen Hegelund admin = vcap_find_admin(vctrl, dst_cid);
1692392d0ab0SSteen Hegelund if (!admin)
1693392d0ab0SSteen Hegelund return false;
1694392d0ab0SSteen Hegelund
1695784c3067SSteen Hegelund return true;
1696392d0ab0SSteen Hegelund }
1697392d0ab0SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_is_next_lookup);
1698392d0ab0SSteen Hegelund
16998e10490bSSteen Hegelund /* Check if there is room for a new rule */
vcap_rule_space(struct vcap_admin * admin,int size)17008e10490bSSteen Hegelund static int vcap_rule_space(struct vcap_admin *admin, int size)
17018e10490bSSteen Hegelund {
17028e10490bSSteen Hegelund if (admin->last_used_addr - size < admin->first_valid_addr) {
17038e10490bSSteen Hegelund pr_err("%s:%d: No room for rule size: %u, %u\n",
17048e10490bSSteen Hegelund __func__, __LINE__, size, admin->first_valid_addr);
17058e10490bSSteen Hegelund return -ENOSPC;
17068e10490bSSteen Hegelund }
17078e10490bSSteen Hegelund return 0;
17088e10490bSSteen Hegelund }
17098e10490bSSteen Hegelund
17108e10490bSSteen Hegelund /* Add the keyset typefield to the list of rule keyfields */
vcap_add_type_keyfield(struct vcap_rule * rule)17118e10490bSSteen Hegelund static int vcap_add_type_keyfield(struct vcap_rule *rule)
17128e10490bSSteen Hegelund {
17138e10490bSSteen Hegelund struct vcap_rule_internal *ri = to_intrule(rule);
17148e10490bSSteen Hegelund enum vcap_keyfield_set keyset = rule->keyset;
17158e10490bSSteen Hegelund enum vcap_type vt = ri->admin->vtype;
17168e10490bSSteen Hegelund const struct vcap_field *fields;
17178e10490bSSteen Hegelund const struct vcap_set *kset;
17188e10490bSSteen Hegelund int ret = -EINVAL;
17198e10490bSSteen Hegelund
17208e10490bSSteen Hegelund kset = vcap_keyfieldset(ri->vctrl, vt, keyset);
17218e10490bSSteen Hegelund if (!kset)
17228e10490bSSteen Hegelund return ret;
17238e10490bSSteen Hegelund if (kset->type_id == (u8)-1) /* No type field is needed */
17248e10490bSSteen Hegelund return 0;
17258e10490bSSteen Hegelund
17268e10490bSSteen Hegelund fields = vcap_keyfields(ri->vctrl, vt, keyset);
17278e10490bSSteen Hegelund if (!fields)
17288e10490bSSteen Hegelund return -EINVAL;
17298e10490bSSteen Hegelund if (fields[VCAP_KF_TYPE].width > 1) {
17308e10490bSSteen Hegelund ret = vcap_rule_add_key_u32(rule, VCAP_KF_TYPE,
17318e10490bSSteen Hegelund kset->type_id, 0xff);
17328e10490bSSteen Hegelund } else {
17338e10490bSSteen Hegelund if (kset->type_id)
17348e10490bSSteen Hegelund ret = vcap_rule_add_key_bit(rule, VCAP_KF_TYPE,
17358e10490bSSteen Hegelund VCAP_BIT_1);
17368e10490bSSteen Hegelund else
17378e10490bSSteen Hegelund ret = vcap_rule_add_key_bit(rule, VCAP_KF_TYPE,
17388e10490bSSteen Hegelund VCAP_BIT_0);
17398e10490bSSteen Hegelund }
17408e10490bSSteen Hegelund return 0;
17418e10490bSSteen Hegelund }
17428e10490bSSteen Hegelund
17437306fcd1SSteen Hegelund /* Add the actionset typefield to the list of rule actionfields */
vcap_add_type_actionfield(struct vcap_rule * rule)17447306fcd1SSteen Hegelund static int vcap_add_type_actionfield(struct vcap_rule *rule)
17457306fcd1SSteen Hegelund {
17467306fcd1SSteen Hegelund enum vcap_actionfield_set actionset = rule->actionset;
17477306fcd1SSteen Hegelund struct vcap_rule_internal *ri = to_intrule(rule);
17487306fcd1SSteen Hegelund enum vcap_type vt = ri->admin->vtype;
17497306fcd1SSteen Hegelund const struct vcap_field *fields;
17507306fcd1SSteen Hegelund const struct vcap_set *aset;
17517306fcd1SSteen Hegelund int ret = -EINVAL;
17527306fcd1SSteen Hegelund
17537306fcd1SSteen Hegelund aset = vcap_actionfieldset(ri->vctrl, vt, actionset);
17547306fcd1SSteen Hegelund if (!aset)
17557306fcd1SSteen Hegelund return ret;
17567306fcd1SSteen Hegelund if (aset->type_id == (u8)-1) /* No type field is needed */
17577306fcd1SSteen Hegelund return 0;
17587306fcd1SSteen Hegelund
17597306fcd1SSteen Hegelund fields = vcap_actionfields(ri->vctrl, vt, actionset);
17607306fcd1SSteen Hegelund if (!fields)
17617306fcd1SSteen Hegelund return -EINVAL;
17627306fcd1SSteen Hegelund if (fields[VCAP_AF_TYPE].width > 1) {
17637306fcd1SSteen Hegelund ret = vcap_rule_add_action_u32(rule, VCAP_AF_TYPE,
17647306fcd1SSteen Hegelund aset->type_id);
17657306fcd1SSteen Hegelund } else {
17667306fcd1SSteen Hegelund if (aset->type_id)
17677306fcd1SSteen Hegelund ret = vcap_rule_add_action_bit(rule, VCAP_AF_TYPE,
17687306fcd1SSteen Hegelund VCAP_BIT_1);
17697306fcd1SSteen Hegelund else
17707306fcd1SSteen Hegelund ret = vcap_rule_add_action_bit(rule, VCAP_AF_TYPE,
17717306fcd1SSteen Hegelund VCAP_BIT_0);
17727306fcd1SSteen Hegelund }
17737306fcd1SSteen Hegelund return ret;
17747306fcd1SSteen Hegelund }
17757306fcd1SSteen Hegelund
1776abc4010dSSteen Hegelund /* Add a keyset to a keyset list */
vcap_keyset_list_add(struct vcap_keyset_list * keysetlist,enum vcap_keyfield_set keyset)1777abc4010dSSteen Hegelund bool vcap_keyset_list_add(struct vcap_keyset_list *keysetlist,
1778abc4010dSSteen Hegelund enum vcap_keyfield_set keyset)
1779abc4010dSSteen Hegelund {
1780abc4010dSSteen Hegelund int idx;
1781abc4010dSSteen Hegelund
1782abc4010dSSteen Hegelund if (keysetlist->cnt < keysetlist->max) {
1783abc4010dSSteen Hegelund /* Avoid duplicates */
1784abc4010dSSteen Hegelund for (idx = 0; idx < keysetlist->cnt; ++idx)
1785abc4010dSSteen Hegelund if (keysetlist->keysets[idx] == keyset)
1786abc4010dSSteen Hegelund return keysetlist->cnt < keysetlist->max;
1787abc4010dSSteen Hegelund keysetlist->keysets[keysetlist->cnt++] = keyset;
1788abc4010dSSteen Hegelund }
1789abc4010dSSteen Hegelund return keysetlist->cnt < keysetlist->max;
1790abc4010dSSteen Hegelund }
1791abc4010dSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_keyset_list_add);
1792abc4010dSSteen Hegelund
179381e164c4SSteen Hegelund /* Add a actionset to a actionset list */
vcap_actionset_list_add(struct vcap_actionset_list * actionsetlist,enum vcap_actionfield_set actionset)179481e164c4SSteen Hegelund static bool vcap_actionset_list_add(struct vcap_actionset_list *actionsetlist,
179581e164c4SSteen Hegelund enum vcap_actionfield_set actionset)
179681e164c4SSteen Hegelund {
179781e164c4SSteen Hegelund int idx;
179881e164c4SSteen Hegelund
179981e164c4SSteen Hegelund if (actionsetlist->cnt < actionsetlist->max) {
180081e164c4SSteen Hegelund /* Avoid duplicates */
180181e164c4SSteen Hegelund for (idx = 0; idx < actionsetlist->cnt; ++idx)
180281e164c4SSteen Hegelund if (actionsetlist->actionsets[idx] == actionset)
180381e164c4SSteen Hegelund return actionsetlist->cnt < actionsetlist->max;
180481e164c4SSteen Hegelund actionsetlist->actionsets[actionsetlist->cnt++] = actionset;
180581e164c4SSteen Hegelund }
180681e164c4SSteen Hegelund return actionsetlist->cnt < actionsetlist->max;
180781e164c4SSteen Hegelund }
180881e164c4SSteen Hegelund
1809abc4010dSSteen Hegelund /* map keyset id to a string with the keyset name */
vcap_keyset_name(struct vcap_control * vctrl,enum vcap_keyfield_set keyset)1810abc4010dSSteen Hegelund const char *vcap_keyset_name(struct vcap_control *vctrl,
1811abc4010dSSteen Hegelund enum vcap_keyfield_set keyset)
1812abc4010dSSteen Hegelund {
1813abc4010dSSteen Hegelund return vctrl->stats->keyfield_set_names[keyset];
1814abc4010dSSteen Hegelund }
1815abc4010dSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_keyset_name);
1816abc4010dSSteen Hegelund
1817abc4010dSSteen Hegelund /* map key field id to a string with the key name */
vcap_keyfield_name(struct vcap_control * vctrl,enum vcap_key_field key)1818abc4010dSSteen Hegelund const char *vcap_keyfield_name(struct vcap_control *vctrl,
1819abc4010dSSteen Hegelund enum vcap_key_field key)
1820abc4010dSSteen Hegelund {
1821abc4010dSSteen Hegelund return vctrl->stats->keyfield_names[key];
1822abc4010dSSteen Hegelund }
1823abc4010dSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_keyfield_name);
1824abc4010dSSteen Hegelund
18253a792156SSteen Hegelund /* map actionset id to a string with the actionset name */
vcap_actionset_name(struct vcap_control * vctrl,enum vcap_actionfield_set actionset)18263a792156SSteen Hegelund const char *vcap_actionset_name(struct vcap_control *vctrl,
18273a792156SSteen Hegelund enum vcap_actionfield_set actionset)
18283a792156SSteen Hegelund {
18293a792156SSteen Hegelund return vctrl->stats->actionfield_set_names[actionset];
18303a792156SSteen Hegelund }
18313a792156SSteen Hegelund
1832242df4f7SSteen Hegelund /* map action field id to a string with the action name */
vcap_actionfield_name(struct vcap_control * vctrl,enum vcap_action_field action)18333a792156SSteen Hegelund const char *vcap_actionfield_name(struct vcap_control *vctrl,
1834242df4f7SSteen Hegelund enum vcap_action_field action)
1835242df4f7SSteen Hegelund {
1836242df4f7SSteen Hegelund return vctrl->stats->actionfield_names[action];
1837242df4f7SSteen Hegelund }
1838242df4f7SSteen Hegelund
1839abc4010dSSteen Hegelund /* Return the keyfield that matches a key in a keyset */
1840abc4010dSSteen Hegelund static const struct vcap_field *
vcap_find_keyset_keyfield(struct vcap_control * vctrl,enum vcap_type vtype,enum vcap_keyfield_set keyset,enum vcap_key_field key)1841abc4010dSSteen Hegelund vcap_find_keyset_keyfield(struct vcap_control *vctrl,
1842abc4010dSSteen Hegelund enum vcap_type vtype,
1843abc4010dSSteen Hegelund enum vcap_keyfield_set keyset,
1844abc4010dSSteen Hegelund enum vcap_key_field key)
1845abc4010dSSteen Hegelund {
1846abc4010dSSteen Hegelund const struct vcap_field *fields;
1847abc4010dSSteen Hegelund int idx, count;
1848abc4010dSSteen Hegelund
1849abc4010dSSteen Hegelund fields = vcap_keyfields(vctrl, vtype, keyset);
1850abc4010dSSteen Hegelund if (!fields)
1851abc4010dSSteen Hegelund return NULL;
1852abc4010dSSteen Hegelund
1853abc4010dSSteen Hegelund /* Iterate the keyfields of the keyset */
1854abc4010dSSteen Hegelund count = vcap_keyfield_count(vctrl, vtype, keyset);
1855abc4010dSSteen Hegelund for (idx = 0; idx < count; ++idx) {
1856abc4010dSSteen Hegelund if (fields[idx].width == 0)
1857abc4010dSSteen Hegelund continue;
1858abc4010dSSteen Hegelund
1859abc4010dSSteen Hegelund if (key == idx)
1860abc4010dSSteen Hegelund return &fields[idx];
1861abc4010dSSteen Hegelund }
1862abc4010dSSteen Hegelund
1863abc4010dSSteen Hegelund return NULL;
1864abc4010dSSteen Hegelund }
1865abc4010dSSteen Hegelund
1866abc4010dSSteen Hegelund /* Match a list of keys against the keysets available in a vcap type */
_vcap_rule_find_keysets(struct vcap_rule_internal * ri,struct vcap_keyset_list * matches)1867465a38a2SSteen Hegelund static bool _vcap_rule_find_keysets(struct vcap_rule_internal *ri,
1868abc4010dSSteen Hegelund struct vcap_keyset_list *matches)
1869abc4010dSSteen Hegelund {
1870abc4010dSSteen Hegelund const struct vcap_client_keyfield *ckf;
1871abc4010dSSteen Hegelund int keyset, found, keycount, map_size;
1872abc4010dSSteen Hegelund const struct vcap_field **map;
1873abc4010dSSteen Hegelund enum vcap_type vtype;
1874abc4010dSSteen Hegelund
1875abc4010dSSteen Hegelund vtype = ri->admin->vtype;
1876abc4010dSSteen Hegelund map = ri->vctrl->vcaps[vtype].keyfield_set_map;
1877abc4010dSSteen Hegelund map_size = ri->vctrl->vcaps[vtype].keyfield_set_size;
1878abc4010dSSteen Hegelund
1879abc4010dSSteen Hegelund /* Get a count of the keyfields we want to match */
1880abc4010dSSteen Hegelund keycount = 0;
1881abc4010dSSteen Hegelund list_for_each_entry(ckf, &ri->data.keyfields, ctrl.list)
1882abc4010dSSteen Hegelund ++keycount;
1883abc4010dSSteen Hegelund
1884abc4010dSSteen Hegelund matches->cnt = 0;
1885abc4010dSSteen Hegelund /* Iterate the keysets of the VCAP */
1886abc4010dSSteen Hegelund for (keyset = 0; keyset < map_size; ++keyset) {
1887abc4010dSSteen Hegelund if (!map[keyset])
1888abc4010dSSteen Hegelund continue;
1889abc4010dSSteen Hegelund
1890abc4010dSSteen Hegelund /* Iterate the keys in the rule */
1891abc4010dSSteen Hegelund found = 0;
1892abc4010dSSteen Hegelund list_for_each_entry(ckf, &ri->data.keyfields, ctrl.list)
1893abc4010dSSteen Hegelund if (vcap_find_keyset_keyfield(ri->vctrl, vtype,
1894abc4010dSSteen Hegelund keyset, ckf->ctrl.key))
1895abc4010dSSteen Hegelund ++found;
1896abc4010dSSteen Hegelund
1897abc4010dSSteen Hegelund /* Save the keyset if all keyfields were found */
1898abc4010dSSteen Hegelund if (found == keycount)
1899abc4010dSSteen Hegelund if (!vcap_keyset_list_add(matches, keyset))
1900abc4010dSSteen Hegelund /* bail out when the quota is filled */
1901abc4010dSSteen Hegelund break;
1902abc4010dSSteen Hegelund }
1903abc4010dSSteen Hegelund
1904abc4010dSSteen Hegelund return matches->cnt > 0;
1905abc4010dSSteen Hegelund }
1906abc4010dSSteen Hegelund
1907465a38a2SSteen Hegelund /* Match a list of keys against the keysets available in a vcap type */
vcap_rule_find_keysets(struct vcap_rule * rule,struct vcap_keyset_list * matches)1908465a38a2SSteen Hegelund bool vcap_rule_find_keysets(struct vcap_rule *rule,
1909465a38a2SSteen Hegelund struct vcap_keyset_list *matches)
1910465a38a2SSteen Hegelund {
1911465a38a2SSteen Hegelund struct vcap_rule_internal *ri = to_intrule(rule);
1912465a38a2SSteen Hegelund
1913465a38a2SSteen Hegelund return _vcap_rule_find_keysets(ri, matches);
1914465a38a2SSteen Hegelund }
1915465a38a2SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_find_keysets);
1916465a38a2SSteen Hegelund
191781e164c4SSteen Hegelund /* Return the actionfield that matches a action in a actionset */
191881e164c4SSteen Hegelund static const struct vcap_field *
vcap_find_actionset_actionfield(struct vcap_control * vctrl,enum vcap_type vtype,enum vcap_actionfield_set actionset,enum vcap_action_field action)191981e164c4SSteen Hegelund vcap_find_actionset_actionfield(struct vcap_control *vctrl,
192081e164c4SSteen Hegelund enum vcap_type vtype,
192181e164c4SSteen Hegelund enum vcap_actionfield_set actionset,
192281e164c4SSteen Hegelund enum vcap_action_field action)
192381e164c4SSteen Hegelund {
192481e164c4SSteen Hegelund const struct vcap_field *fields;
192581e164c4SSteen Hegelund int idx, count;
192681e164c4SSteen Hegelund
192781e164c4SSteen Hegelund fields = vcap_actionfields(vctrl, vtype, actionset);
192881e164c4SSteen Hegelund if (!fields)
192981e164c4SSteen Hegelund return NULL;
193081e164c4SSteen Hegelund
193181e164c4SSteen Hegelund /* Iterate the actionfields of the actionset */
193281e164c4SSteen Hegelund count = vcap_actionfield_count(vctrl, vtype, actionset);
193381e164c4SSteen Hegelund for (idx = 0; idx < count; ++idx) {
193481e164c4SSteen Hegelund if (fields[idx].width == 0)
193581e164c4SSteen Hegelund continue;
193681e164c4SSteen Hegelund
193781e164c4SSteen Hegelund if (action == idx)
193881e164c4SSteen Hegelund return &fields[idx];
193981e164c4SSteen Hegelund }
194081e164c4SSteen Hegelund
194181e164c4SSteen Hegelund return NULL;
194281e164c4SSteen Hegelund }
194381e164c4SSteen Hegelund
194481e164c4SSteen Hegelund /* Match a list of actions against the actionsets available in a vcap type */
vcap_rule_find_actionsets(struct vcap_rule_internal * ri,struct vcap_actionset_list * matches)194581e164c4SSteen Hegelund static bool vcap_rule_find_actionsets(struct vcap_rule_internal *ri,
194681e164c4SSteen Hegelund struct vcap_actionset_list *matches)
194781e164c4SSteen Hegelund {
194881e164c4SSteen Hegelund int actionset, found, actioncount, map_size;
194981e164c4SSteen Hegelund const struct vcap_client_actionfield *ckf;
195081e164c4SSteen Hegelund const struct vcap_field **map;
195181e164c4SSteen Hegelund enum vcap_type vtype;
195281e164c4SSteen Hegelund
195381e164c4SSteen Hegelund vtype = ri->admin->vtype;
195481e164c4SSteen Hegelund map = ri->vctrl->vcaps[vtype].actionfield_set_map;
195581e164c4SSteen Hegelund map_size = ri->vctrl->vcaps[vtype].actionfield_set_size;
195681e164c4SSteen Hegelund
195781e164c4SSteen Hegelund /* Get a count of the actionfields we want to match */
195881e164c4SSteen Hegelund actioncount = 0;
195981e164c4SSteen Hegelund list_for_each_entry(ckf, &ri->data.actionfields, ctrl.list)
196081e164c4SSteen Hegelund ++actioncount;
196181e164c4SSteen Hegelund
196281e164c4SSteen Hegelund matches->cnt = 0;
196381e164c4SSteen Hegelund /* Iterate the actionsets of the VCAP */
196481e164c4SSteen Hegelund for (actionset = 0; actionset < map_size; ++actionset) {
196581e164c4SSteen Hegelund if (!map[actionset])
196681e164c4SSteen Hegelund continue;
196781e164c4SSteen Hegelund
196881e164c4SSteen Hegelund /* Iterate the actions in the rule */
196981e164c4SSteen Hegelund found = 0;
197081e164c4SSteen Hegelund list_for_each_entry(ckf, &ri->data.actionfields, ctrl.list)
197181e164c4SSteen Hegelund if (vcap_find_actionset_actionfield(ri->vctrl, vtype,
197281e164c4SSteen Hegelund actionset,
197381e164c4SSteen Hegelund ckf->ctrl.action))
197481e164c4SSteen Hegelund ++found;
197581e164c4SSteen Hegelund
197681e164c4SSteen Hegelund /* Save the actionset if all actionfields were found */
197781e164c4SSteen Hegelund if (found == actioncount)
197881e164c4SSteen Hegelund if (!vcap_actionset_list_add(matches, actionset))
197981e164c4SSteen Hegelund /* bail out when the quota is filled */
198081e164c4SSteen Hegelund break;
198181e164c4SSteen Hegelund }
198281e164c4SSteen Hegelund
198381e164c4SSteen Hegelund return matches->cnt > 0;
198481e164c4SSteen Hegelund }
198581e164c4SSteen Hegelund
1986c9da1ac1SSteen Hegelund /* Validate a rule with respect to available port keys */
vcap_val_rule(struct vcap_rule * rule,u16 l3_proto)1987c9da1ac1SSteen Hegelund int vcap_val_rule(struct vcap_rule *rule, u16 l3_proto)
1988c9da1ac1SSteen Hegelund {
1989c9da1ac1SSteen Hegelund struct vcap_rule_internal *ri = to_intrule(rule);
1990abc4010dSSteen Hegelund struct vcap_keyset_list matches = {};
19918e10490bSSteen Hegelund enum vcap_keyfield_set keysets[10];
19928e10490bSSteen Hegelund int ret;
1993c9da1ac1SSteen Hegelund
19948e10490bSSteen Hegelund ret = vcap_api_check(ri->vctrl);
19958e10490bSSteen Hegelund if (ret)
19968e10490bSSteen Hegelund return ret;
1997c9da1ac1SSteen Hegelund if (!ri->admin) {
1998c9da1ac1SSteen Hegelund ri->data.exterr = VCAP_ERR_NO_ADMIN;
1999c9da1ac1SSteen Hegelund return -EINVAL;
2000c9da1ac1SSteen Hegelund }
2001c9da1ac1SSteen Hegelund if (!ri->ndev) {
2002c9da1ac1SSteen Hegelund ri->data.exterr = VCAP_ERR_NO_NETDEV;
2003c9da1ac1SSteen Hegelund return -EINVAL;
2004c9da1ac1SSteen Hegelund }
2005abc4010dSSteen Hegelund
2006abc4010dSSteen Hegelund matches.keysets = keysets;
2007abc4010dSSteen Hegelund matches.max = ARRAY_SIZE(keysets);
2008c9da1ac1SSteen Hegelund if (ri->data.keyset == VCAP_KFS_NO_VALUE) {
2009abc4010dSSteen Hegelund /* Iterate over rule keyfields and select keysets that fits */
2010465a38a2SSteen Hegelund if (!_vcap_rule_find_keysets(ri, &matches)) {
2011c9da1ac1SSteen Hegelund ri->data.exterr = VCAP_ERR_NO_KEYSET_MATCH;
2012c9da1ac1SSteen Hegelund return -EINVAL;
2013c9da1ac1SSteen Hegelund }
2014abc4010dSSteen Hegelund } else {
20158e10490bSSteen Hegelund /* prepare for keyset validation */
20168e10490bSSteen Hegelund keysets[0] = ri->data.keyset;
2017abc4010dSSteen Hegelund matches.cnt = 1;
2018abc4010dSSteen Hegelund }
2019abc4010dSSteen Hegelund
20208e10490bSSteen Hegelund /* Pick a keyset that is supported in the port lookups */
2021abc4010dSSteen Hegelund ret = ri->vctrl->ops->validate_keyset(ri->ndev, ri->admin, rule,
2022abc4010dSSteen Hegelund &matches, l3_proto);
20238e10490bSSteen Hegelund if (ret < 0) {
20248e10490bSSteen Hegelund pr_err("%s:%d: keyset validation failed: %d\n",
20258e10490bSSteen Hegelund __func__, __LINE__, ret);
20268e10490bSSteen Hegelund ri->data.exterr = VCAP_ERR_NO_PORT_KEYSET_MATCH;
20278e10490bSSteen Hegelund return ret;
20288e10490bSSteen Hegelund }
2029abc4010dSSteen Hegelund /* use the keyset that is supported in the port lookups */
2030abc4010dSSteen Hegelund ret = vcap_set_rule_set_keyset(rule, ret);
2031abc4010dSSteen Hegelund if (ret < 0) {
2032abc4010dSSteen Hegelund pr_err("%s:%d: keyset was not updated: %d\n",
2033abc4010dSSteen Hegelund __func__, __LINE__, ret);
2034abc4010dSSteen Hegelund return ret;
2035abc4010dSSteen Hegelund }
2036c9da1ac1SSteen Hegelund if (ri->data.actionset == VCAP_AFS_NO_VALUE) {
203781e164c4SSteen Hegelund struct vcap_actionset_list matches = {};
203881e164c4SSteen Hegelund enum vcap_actionfield_set actionsets[10];
203981e164c4SSteen Hegelund
204081e164c4SSteen Hegelund matches.actionsets = actionsets;
204181e164c4SSteen Hegelund matches.max = ARRAY_SIZE(actionsets);
204281e164c4SSteen Hegelund
204381e164c4SSteen Hegelund /* Find an actionset that fits the rule actions */
204481e164c4SSteen Hegelund if (!vcap_rule_find_actionsets(ri, &matches)) {
2045c9da1ac1SSteen Hegelund ri->data.exterr = VCAP_ERR_NO_ACTIONSET_MATCH;
2046c9da1ac1SSteen Hegelund return -EINVAL;
2047c9da1ac1SSteen Hegelund }
204881e164c4SSteen Hegelund ret = vcap_set_rule_set_actionset(rule, actionsets[0]);
204981e164c4SSteen Hegelund if (ret < 0) {
205081e164c4SSteen Hegelund pr_err("%s:%d: actionset was not updated: %d\n",
205181e164c4SSteen Hegelund __func__, __LINE__, ret);
205281e164c4SSteen Hegelund return ret;
205381e164c4SSteen Hegelund }
205481e164c4SSteen Hegelund }
20558e10490bSSteen Hegelund vcap_add_type_keyfield(rule);
20567306fcd1SSteen Hegelund vcap_add_type_actionfield(rule);
20578e10490bSSteen Hegelund /* Add default fields to this rule */
20588e10490bSSteen Hegelund ri->vctrl->ops->add_default_fields(ri->ndev, ri->admin, rule);
20598e10490bSSteen Hegelund
20608e10490bSSteen Hegelund /* Rule size is the maximum of the entry and action subword count */
20618e10490bSSteen Hegelund ri->size = max(ri->keyset_sw, ri->actionset_sw);
20628e10490bSSteen Hegelund
20638e10490bSSteen Hegelund /* Finally check if there is room for the rule in the VCAP */
20648e10490bSSteen Hegelund return vcap_rule_space(ri->admin, ri->size);
2065c9da1ac1SSteen Hegelund }
2066c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_val_rule);
2067c9da1ac1SSteen Hegelund
2068990e4839SSteen Hegelund /* Entries are sorted with increasing values of sort_key.
2069990e4839SSteen Hegelund * I.e. Lowest numerical sort_key is first in list.
2070990e4839SSteen Hegelund * In order to locate largest keys first in list we negate the key size with
2071990e4839SSteen Hegelund * (max_size - size).
2072990e4839SSteen Hegelund */
vcap_sort_key(u32 max_size,u32 size,u8 user,u16 prio)2073990e4839SSteen Hegelund static u32 vcap_sort_key(u32 max_size, u32 size, u8 user, u16 prio)
2074990e4839SSteen Hegelund {
2075990e4839SSteen Hegelund return ((max_size - size) << 24) | (user << 16) | prio;
2076990e4839SSteen Hegelund }
2077990e4839SSteen Hegelund
20788e10490bSSteen Hegelund /* calculate the address of the next rule after this (lower address and prio) */
vcap_next_rule_addr(u32 addr,struct vcap_rule_internal * ri)20798e10490bSSteen Hegelund static u32 vcap_next_rule_addr(u32 addr, struct vcap_rule_internal *ri)
20808e10490bSSteen Hegelund {
20818e10490bSSteen Hegelund return ((addr - ri->size) / ri->size) * ri->size;
20828e10490bSSteen Hegelund }
20838e10490bSSteen Hegelund
2084c9da1ac1SSteen Hegelund /* Assign a unique rule id and autogenerate one if id == 0 */
vcap_set_rule_id(struct vcap_rule_internal * ri)2085c9da1ac1SSteen Hegelund static u32 vcap_set_rule_id(struct vcap_rule_internal *ri)
2086c9da1ac1SSteen Hegelund {
2087c9da1ac1SSteen Hegelund if (ri->data.id != 0)
2088c9da1ac1SSteen Hegelund return ri->data.id;
2089c9da1ac1SSteen Hegelund
2090c1d8e3fbSHoratiu Vultur for (u32 next_id = 1; next_id < ~0; ++next_id) {
2091975d86acSSteen Hegelund if (!vcap_rule_exists(ri->vctrl, next_id)) {
2092c9da1ac1SSteen Hegelund ri->data.id = next_id;
2093c9da1ac1SSteen Hegelund break;
2094c9da1ac1SSteen Hegelund }
2095c9da1ac1SSteen Hegelund }
2096c9da1ac1SSteen Hegelund return ri->data.id;
2097c9da1ac1SSteen Hegelund }
2098c9da1ac1SSteen Hegelund
vcap_insert_rule(struct vcap_rule_internal * ri,struct vcap_rule_move * move)20998e10490bSSteen Hegelund static int vcap_insert_rule(struct vcap_rule_internal *ri,
21008e10490bSSteen Hegelund struct vcap_rule_move *move)
21018e10490bSSteen Hegelund {
2102990e4839SSteen Hegelund int sw_count = ri->vctrl->vcaps[ri->admin->vtype].sw_count;
2103990e4839SSteen Hegelund struct vcap_rule_internal *duprule, *iter, *elem = NULL;
21048e10490bSSteen Hegelund struct vcap_admin *admin = ri->admin;
2105990e4839SSteen Hegelund u32 addr;
21068e10490bSSteen Hegelund
2107990e4839SSteen Hegelund ri->sort_key = vcap_sort_key(sw_count, ri->size, ri->data.user,
2108990e4839SSteen Hegelund ri->data.priority);
2109990e4839SSteen Hegelund
2110990e4839SSteen Hegelund /* Insert the new rule in the list of rule based on the sort key
2111990e4839SSteen Hegelund * If the rule needs to be inserted between existing rules then move
2112990e4839SSteen Hegelund * these rules to make room for the new rule and update their start
2113990e4839SSteen Hegelund * address.
2114990e4839SSteen Hegelund */
2115990e4839SSteen Hegelund list_for_each_entry(iter, &admin->rules, list) {
2116990e4839SSteen Hegelund if (ri->sort_key < iter->sort_key) {
2117990e4839SSteen Hegelund elem = iter;
2118990e4839SSteen Hegelund break;
2119990e4839SSteen Hegelund }
2120990e4839SSteen Hegelund }
2121990e4839SSteen Hegelund
2122990e4839SSteen Hegelund if (!elem) {
21238e10490bSSteen Hegelund ri->addr = vcap_next_rule_addr(admin->last_used_addr, ri);
21248e10490bSSteen Hegelund admin->last_used_addr = ri->addr;
2125990e4839SSteen Hegelund
2126814e7693SSteen Hegelund /* Add a copy of the rule to the VCAP list */
2127814e7693SSteen Hegelund duprule = vcap_dup_rule(ri, ri->state == VCAP_RS_DISABLED);
21288e10490bSSteen Hegelund if (IS_ERR(duprule))
21298e10490bSSteen Hegelund return PTR_ERR(duprule);
2130990e4839SSteen Hegelund
21318e10490bSSteen Hegelund list_add_tail(&duprule->list, &admin->rules);
21328e10490bSSteen Hegelund return 0;
21338e10490bSSteen Hegelund }
21348e10490bSSteen Hegelund
2135990e4839SSteen Hegelund /* Reuse the space of the current rule */
2136990e4839SSteen Hegelund addr = elem->addr + elem->size;
2137990e4839SSteen Hegelund ri->addr = vcap_next_rule_addr(addr, ri);
2138990e4839SSteen Hegelund addr = ri->addr;
2139990e4839SSteen Hegelund
2140814e7693SSteen Hegelund /* Add a copy of the rule to the VCAP list */
2141814e7693SSteen Hegelund duprule = vcap_dup_rule(ri, ri->state == VCAP_RS_DISABLED);
2142990e4839SSteen Hegelund if (IS_ERR(duprule))
2143990e4839SSteen Hegelund return PTR_ERR(duprule);
2144990e4839SSteen Hegelund
2145990e4839SSteen Hegelund /* Add before the current entry */
2146990e4839SSteen Hegelund list_add_tail(&duprule->list, &elem->list);
2147990e4839SSteen Hegelund
2148990e4839SSteen Hegelund /* Update the current rule */
2149990e4839SSteen Hegelund elem->addr = vcap_next_rule_addr(addr, elem);
2150990e4839SSteen Hegelund addr = elem->addr;
2151990e4839SSteen Hegelund
2152990e4839SSteen Hegelund /* Update the address in the remaining rules in the list */
2153990e4839SSteen Hegelund list_for_each_entry_continue(elem, &admin->rules, list) {
2154990e4839SSteen Hegelund elem->addr = vcap_next_rule_addr(addr, elem);
2155990e4839SSteen Hegelund addr = elem->addr;
2156990e4839SSteen Hegelund }
2157990e4839SSteen Hegelund
2158990e4839SSteen Hegelund /* Update the move info */
2159990e4839SSteen Hegelund move->addr = admin->last_used_addr;
2160990e4839SSteen Hegelund move->count = ri->addr - addr;
2161990e4839SSteen Hegelund move->offset = admin->last_used_addr - addr;
2162990e4839SSteen Hegelund admin->last_used_addr = addr;
2163990e4839SSteen Hegelund return 0;
2164990e4839SSteen Hegelund }
2165990e4839SSteen Hegelund
vcap_move_rules(struct vcap_rule_internal * ri,struct vcap_rule_move * move)21668e10490bSSteen Hegelund static void vcap_move_rules(struct vcap_rule_internal *ri,
21678e10490bSSteen Hegelund struct vcap_rule_move *move)
21688e10490bSSteen Hegelund {
21698e10490bSSteen Hegelund ri->vctrl->ops->move(ri->ndev, ri->admin, move->addr,
21708e10490bSSteen Hegelund move->offset, move->count);
21718e10490bSSteen Hegelund }
21728e10490bSSteen Hegelund
2173cfd9e7b7SSteen Hegelund /* Check if the chain is already used to enable a VCAP lookup for this port */
vcap_is_chain_used(struct vcap_control * vctrl,struct net_device * ndev,int src_cid)2174cfd9e7b7SSteen Hegelund static bool vcap_is_chain_used(struct vcap_control *vctrl,
2175cfd9e7b7SSteen Hegelund struct net_device *ndev, int src_cid)
2176cfd9e7b7SSteen Hegelund {
2177cfd9e7b7SSteen Hegelund struct vcap_enabled_port *eport;
2178cfd9e7b7SSteen Hegelund struct vcap_admin *admin;
2179cfd9e7b7SSteen Hegelund
2180cfd9e7b7SSteen Hegelund list_for_each_entry(admin, &vctrl->list, list)
2181cfd9e7b7SSteen Hegelund list_for_each_entry(eport, &admin->enabled, list)
2182cfd9e7b7SSteen Hegelund if (eport->src_cid == src_cid && eport->ndev == ndev)
2183cfd9e7b7SSteen Hegelund return true;
2184cfd9e7b7SSteen Hegelund
2185cfd9e7b7SSteen Hegelund return false;
2186cfd9e7b7SSteen Hegelund }
2187cfd9e7b7SSteen Hegelund
2188814e7693SSteen Hegelund /* Fetch the next chain in the enabled list for the port */
vcap_get_next_chain(struct vcap_control * vctrl,struct net_device * ndev,int dst_cid)2189814e7693SSteen Hegelund static int vcap_get_next_chain(struct vcap_control *vctrl,
2190814e7693SSteen Hegelund struct net_device *ndev,
2191814e7693SSteen Hegelund int dst_cid)
2192814e7693SSteen Hegelund {
2193814e7693SSteen Hegelund struct vcap_enabled_port *eport;
2194814e7693SSteen Hegelund struct vcap_admin *admin;
2195814e7693SSteen Hegelund
2196814e7693SSteen Hegelund list_for_each_entry(admin, &vctrl->list, list) {
2197814e7693SSteen Hegelund list_for_each_entry(eport, &admin->enabled, list) {
2198814e7693SSteen Hegelund if (eport->ndev != ndev)
2199814e7693SSteen Hegelund continue;
2200814e7693SSteen Hegelund if (eport->src_cid == dst_cid)
2201814e7693SSteen Hegelund return eport->dst_cid;
2202814e7693SSteen Hegelund }
2203814e7693SSteen Hegelund }
2204814e7693SSteen Hegelund
2205814e7693SSteen Hegelund return 0;
2206814e7693SSteen Hegelund }
2207814e7693SSteen Hegelund
vcap_path_exist(struct vcap_control * vctrl,struct net_device * ndev,int dst_cid)2208814e7693SSteen Hegelund static bool vcap_path_exist(struct vcap_control *vctrl, struct net_device *ndev,
2209814e7693SSteen Hegelund int dst_cid)
2210814e7693SSteen Hegelund {
22110518e914SSteen Hegelund int cid = rounddown(dst_cid, VCAP_CID_LOOKUP_SIZE);
22123bee9b57SDan Carpenter struct vcap_enabled_port *eport = NULL;
22133bee9b57SDan Carpenter struct vcap_enabled_port *elem;
2214814e7693SSteen Hegelund struct vcap_admin *admin;
2215814e7693SSteen Hegelund int tmp;
2216814e7693SSteen Hegelund
22170518e914SSteen Hegelund if (cid == 0) /* Chain zero is always available */
221818a15c76SSteen Hegelund return true;
221918a15c76SSteen Hegelund
2220814e7693SSteen Hegelund /* Find first entry that starts from chain 0*/
2221814e7693SSteen Hegelund list_for_each_entry(admin, &vctrl->list, list) {
2222814e7693SSteen Hegelund list_for_each_entry(elem, &admin->enabled, list) {
2223814e7693SSteen Hegelund if (elem->src_cid == 0 && elem->ndev == ndev) {
2224814e7693SSteen Hegelund eport = elem;
2225814e7693SSteen Hegelund break;
2226814e7693SSteen Hegelund }
2227814e7693SSteen Hegelund }
2228814e7693SSteen Hegelund if (eport)
2229814e7693SSteen Hegelund break;
2230814e7693SSteen Hegelund }
2231814e7693SSteen Hegelund
2232814e7693SSteen Hegelund if (!eport)
2233814e7693SSteen Hegelund return false;
2234814e7693SSteen Hegelund
2235814e7693SSteen Hegelund tmp = eport->dst_cid;
22360518e914SSteen Hegelund while (tmp != cid && tmp != 0)
2237814e7693SSteen Hegelund tmp = vcap_get_next_chain(vctrl, ndev, tmp);
2238814e7693SSteen Hegelund
2239814e7693SSteen Hegelund return !!tmp;
2240814e7693SSteen Hegelund }
2241814e7693SSteen Hegelund
2242814e7693SSteen Hegelund /* Internal clients can always store their rules in HW
2243814e7693SSteen Hegelund * External clients can store their rules if the chain is enabled all
2244814e7693SSteen Hegelund * the way from chain 0, otherwise the rule will be cached until
2245814e7693SSteen Hegelund * the chain is enabled.
2246814e7693SSteen Hegelund */
vcap_rule_set_state(struct vcap_rule_internal * ri)2247814e7693SSteen Hegelund static void vcap_rule_set_state(struct vcap_rule_internal *ri)
2248814e7693SSteen Hegelund {
2249814e7693SSteen Hegelund if (ri->data.user <= VCAP_USER_QOS)
2250814e7693SSteen Hegelund ri->state = VCAP_RS_PERMANENT;
2251814e7693SSteen Hegelund else if (vcap_path_exist(ri->vctrl, ri->ndev, ri->data.vcap_chain_id))
2252814e7693SSteen Hegelund ri->state = VCAP_RS_ENABLED;
2253814e7693SSteen Hegelund else
2254814e7693SSteen Hegelund ri->state = VCAP_RS_DISABLED;
2255814e7693SSteen Hegelund }
2256814e7693SSteen Hegelund
2257c9da1ac1SSteen Hegelund /* Encode and write a validated rule to the VCAP */
vcap_add_rule(struct vcap_rule * rule)2258c9da1ac1SSteen Hegelund int vcap_add_rule(struct vcap_rule *rule)
2259c9da1ac1SSteen Hegelund {
22608e10490bSSteen Hegelund struct vcap_rule_internal *ri = to_intrule(rule);
22618e10490bSSteen Hegelund struct vcap_rule_move move = {0};
226295fa7414SSteen Hegelund struct vcap_counter ctr = {0};
22638e10490bSSteen Hegelund int ret;
22648e10490bSSteen Hegelund
22658e10490bSSteen Hegelund ret = vcap_api_check(ri->vctrl);
22668e10490bSSteen Hegelund if (ret)
22678e10490bSSteen Hegelund return ret;
22688e10490bSSteen Hegelund /* Insert the new rule in the list of vcap rules */
226971c9de99SSteen Hegelund mutex_lock(&ri->admin->lock);
2270814e7693SSteen Hegelund
2271814e7693SSteen Hegelund vcap_rule_set_state(ri);
22728e10490bSSteen Hegelund ret = vcap_insert_rule(ri, &move);
22738e10490bSSteen Hegelund if (ret < 0) {
22748e10490bSSteen Hegelund pr_err("%s:%d: could not insert rule in vcap list: %d\n",
22758e10490bSSteen Hegelund __func__, __LINE__, ret);
22768e10490bSSteen Hegelund goto out;
22778e10490bSSteen Hegelund }
22788e10490bSSteen Hegelund if (move.count > 0)
22798e10490bSSteen Hegelund vcap_move_rules(ri, &move);
2280814e7693SSteen Hegelund
2281d7953da4SSteen Hegelund /* Set the counter to zero */
2282d7953da4SSteen Hegelund ret = vcap_write_counter(ri, &ctr);
2283d7953da4SSteen Hegelund if (ret)
2284d7953da4SSteen Hegelund goto out;
2285d7953da4SSteen Hegelund
2286814e7693SSteen Hegelund if (ri->state == VCAP_RS_DISABLED) {
2287814e7693SSteen Hegelund /* Erase the rule area */
2288814e7693SSteen Hegelund ri->vctrl->ops->init(ri->ndev, ri->admin, ri->addr, ri->size);
2289814e7693SSteen Hegelund goto out;
2290814e7693SSteen Hegelund }
2291814e7693SSteen Hegelund
22926573f71aSSteen Hegelund vcap_erase_cache(ri);
22938e10490bSSteen Hegelund ret = vcap_encode_rule(ri);
22948e10490bSSteen Hegelund if (ret) {
22958e10490bSSteen Hegelund pr_err("%s:%d: rule encoding error: %d\n", __func__, __LINE__, ret);
22968e10490bSSteen Hegelund goto out;
22978e10490bSSteen Hegelund }
22988e10490bSSteen Hegelund
22998e10490bSSteen Hegelund ret = vcap_write_rule(ri);
230095fa7414SSteen Hegelund if (ret) {
23018e10490bSSteen Hegelund pr_err("%s:%d: rule write error: %d\n", __func__, __LINE__, ret);
230295fa7414SSteen Hegelund goto out;
230395fa7414SSteen Hegelund }
23048e10490bSSteen Hegelund out:
230571c9de99SSteen Hegelund mutex_unlock(&ri->admin->lock);
23068e10490bSSteen Hegelund return ret;
2307c9da1ac1SSteen Hegelund }
2308c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_add_rule);
2309c9da1ac1SSteen Hegelund
2310c9da1ac1SSteen Hegelund /* Allocate a new rule with the provided arguments */
vcap_alloc_rule(struct vcap_control * vctrl,struct net_device * ndev,int vcap_chain_id,enum vcap_user user,u16 priority,u32 id)2311c9da1ac1SSteen Hegelund struct vcap_rule *vcap_alloc_rule(struct vcap_control *vctrl,
2312c9da1ac1SSteen Hegelund struct net_device *ndev, int vcap_chain_id,
2313c9da1ac1SSteen Hegelund enum vcap_user user, u16 priority,
2314c9da1ac1SSteen Hegelund u32 id)
2315c9da1ac1SSteen Hegelund {
2316c9da1ac1SSteen Hegelund struct vcap_rule_internal *ri;
2317c9da1ac1SSteen Hegelund struct vcap_admin *admin;
2318990e4839SSteen Hegelund int err, maxsize;
2319c9da1ac1SSteen Hegelund
2320990e4839SSteen Hegelund err = vcap_api_check(vctrl);
2321990e4839SSteen Hegelund if (err)
2322990e4839SSteen Hegelund return ERR_PTR(err);
2323c9da1ac1SSteen Hegelund if (!ndev)
2324c9da1ac1SSteen Hegelund return ERR_PTR(-ENODEV);
2325c9da1ac1SSteen Hegelund /* Get the VCAP instance */
2326c9da1ac1SSteen Hegelund admin = vcap_find_admin(vctrl, vcap_chain_id);
2327c9da1ac1SSteen Hegelund if (!admin)
2328c9da1ac1SSteen Hegelund return ERR_PTR(-ENOENT);
23298e10490bSSteen Hegelund /* Sanity check that this VCAP is supported on this platform */
23308e10490bSSteen Hegelund if (vctrl->vcaps[admin->vtype].rows == 0)
23318e10490bSSteen Hegelund return ERR_PTR(-EINVAL);
23321972b6d9SSteen Hegelund
23331972b6d9SSteen Hegelund mutex_lock(&admin->lock);
23348e10490bSSteen Hegelund /* Check if a rule with this id already exists */
23351972b6d9SSteen Hegelund if (vcap_rule_exists(vctrl, id)) {
23361972b6d9SSteen Hegelund err = -EINVAL;
23371972b6d9SSteen Hegelund goto out_unlock;
23381972b6d9SSteen Hegelund }
23391972b6d9SSteen Hegelund
23408e10490bSSteen Hegelund /* Check if there is room for the rule in the block(s) of the VCAP */
23418e10490bSSteen Hegelund maxsize = vctrl->vcaps[admin->vtype].sw_count; /* worst case rule size */
23421972b6d9SSteen Hegelund if (vcap_rule_space(admin, maxsize)) {
23431972b6d9SSteen Hegelund err = -ENOSPC;
23441972b6d9SSteen Hegelund goto out_unlock;
23451972b6d9SSteen Hegelund }
23461972b6d9SSteen Hegelund
2347c9da1ac1SSteen Hegelund /* Create a container for the rule and return it */
2348c9da1ac1SSteen Hegelund ri = kzalloc(sizeof(*ri), GFP_KERNEL);
23491972b6d9SSteen Hegelund if (!ri) {
23501972b6d9SSteen Hegelund err = -ENOMEM;
23511972b6d9SSteen Hegelund goto out_unlock;
23521972b6d9SSteen Hegelund }
23531972b6d9SSteen Hegelund
2354c9da1ac1SSteen Hegelund ri->data.vcap_chain_id = vcap_chain_id;
2355c9da1ac1SSteen Hegelund ri->data.user = user;
2356c9da1ac1SSteen Hegelund ri->data.priority = priority;
2357c9da1ac1SSteen Hegelund ri->data.id = id;
2358c9da1ac1SSteen Hegelund ri->data.keyset = VCAP_KFS_NO_VALUE;
2359c9da1ac1SSteen Hegelund ri->data.actionset = VCAP_AFS_NO_VALUE;
2360c9da1ac1SSteen Hegelund INIT_LIST_HEAD(&ri->list);
2361c9da1ac1SSteen Hegelund INIT_LIST_HEAD(&ri->data.keyfields);
2362c9da1ac1SSteen Hegelund INIT_LIST_HEAD(&ri->data.actionfields);
2363c9da1ac1SSteen Hegelund ri->ndev = ndev;
2364c9da1ac1SSteen Hegelund ri->admin = admin; /* refer to the vcap instance */
2365c9da1ac1SSteen Hegelund ri->vctrl = vctrl; /* refer to the client */
23661972b6d9SSteen Hegelund
23671972b6d9SSteen Hegelund if (vcap_set_rule_id(ri) == 0) {
23681972b6d9SSteen Hegelund err = -EINVAL;
2369c9da1ac1SSteen Hegelund goto out_free;
23701972b6d9SSteen Hegelund }
23711972b6d9SSteen Hegelund
23721972b6d9SSteen Hegelund mutex_unlock(&admin->lock);
2373c9da1ac1SSteen Hegelund return (struct vcap_rule *)ri;
2374c9da1ac1SSteen Hegelund
2375c9da1ac1SSteen Hegelund out_free:
2376c9da1ac1SSteen Hegelund kfree(ri);
23771972b6d9SSteen Hegelund out_unlock:
23781972b6d9SSteen Hegelund mutex_unlock(&admin->lock);
23791972b6d9SSteen Hegelund return ERR_PTR(err);
23801972b6d9SSteen Hegelund
2381c9da1ac1SSteen Hegelund }
2382c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_alloc_rule);
2383c9da1ac1SSteen Hegelund
2384c9da1ac1SSteen Hegelund /* Free mem of a rule owned by client after the rule as been added to the VCAP */
vcap_free_rule(struct vcap_rule * rule)2385c9da1ac1SSteen Hegelund void vcap_free_rule(struct vcap_rule *rule)
2386c9da1ac1SSteen Hegelund {
2387c9da1ac1SSteen Hegelund struct vcap_rule_internal *ri = to_intrule(rule);
2388c9da1ac1SSteen Hegelund struct vcap_client_actionfield *caf, *next_caf;
2389c9da1ac1SSteen Hegelund struct vcap_client_keyfield *ckf, *next_ckf;
2390c9da1ac1SSteen Hegelund
2391c9da1ac1SSteen Hegelund /* Deallocate the list of keys and actions */
2392c9da1ac1SSteen Hegelund list_for_each_entry_safe(ckf, next_ckf, &ri->data.keyfields, ctrl.list) {
2393c9da1ac1SSteen Hegelund list_del(&ckf->ctrl.list);
2394c9da1ac1SSteen Hegelund kfree(ckf);
2395c9da1ac1SSteen Hegelund }
2396c9da1ac1SSteen Hegelund list_for_each_entry_safe(caf, next_caf, &ri->data.actionfields, ctrl.list) {
2397c9da1ac1SSteen Hegelund list_del(&caf->ctrl.list);
2398c9da1ac1SSteen Hegelund kfree(caf);
2399c9da1ac1SSteen Hegelund }
2400c9da1ac1SSteen Hegelund /* Deallocate the rule */
2401c9da1ac1SSteen Hegelund kfree(rule);
2402c9da1ac1SSteen Hegelund }
2403c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_free_rule);
2404c9da1ac1SSteen Hegelund
24059579e2c2SSteen Hegelund /* Decode a rule from the VCAP cache and return a copy */
vcap_decode_rule(struct vcap_rule_internal * elem)24069579e2c2SSteen Hegelund struct vcap_rule *vcap_decode_rule(struct vcap_rule_internal *elem)
2407610c32b2SHoratiu Vultur {
2408610c32b2SHoratiu Vultur struct vcap_rule_internal *ri;
2409610c32b2SHoratiu Vultur int err;
2410610c32b2SHoratiu Vultur
24119579e2c2SSteen Hegelund ri = vcap_dup_rule(elem, elem->state == VCAP_RS_DISABLED);
24129579e2c2SSteen Hegelund if (IS_ERR(ri))
241358e70126SLi Zetao return ERR_CAST(ri);
24149579e2c2SSteen Hegelund
24159579e2c2SSteen Hegelund if (ri->state == VCAP_RS_DISABLED)
24169579e2c2SSteen Hegelund goto out;
24179579e2c2SSteen Hegelund
24189579e2c2SSteen Hegelund err = vcap_read_rule(ri);
24199579e2c2SSteen Hegelund if (err)
24209579e2c2SSteen Hegelund return ERR_PTR(err);
24219579e2c2SSteen Hegelund
24229579e2c2SSteen Hegelund err = vcap_decode_keyset(ri);
24239579e2c2SSteen Hegelund if (err)
24249579e2c2SSteen Hegelund return ERR_PTR(err);
24259579e2c2SSteen Hegelund
24269579e2c2SSteen Hegelund err = vcap_decode_actionset(ri);
24279579e2c2SSteen Hegelund if (err)
24289579e2c2SSteen Hegelund return ERR_PTR(err);
24299579e2c2SSteen Hegelund
24309579e2c2SSteen Hegelund out:
24319579e2c2SSteen Hegelund return &ri->data;
24329579e2c2SSteen Hegelund }
24339579e2c2SSteen Hegelund
vcap_get_rule(struct vcap_control * vctrl,u32 id)24349579e2c2SSteen Hegelund struct vcap_rule *vcap_get_rule(struct vcap_control *vctrl, u32 id)
24359579e2c2SSteen Hegelund {
24369579e2c2SSteen Hegelund struct vcap_rule_internal *elem;
24379579e2c2SSteen Hegelund struct vcap_rule *rule;
24389579e2c2SSteen Hegelund int err;
2439610c32b2SHoratiu Vultur
2440610c32b2SHoratiu Vultur err = vcap_api_check(vctrl);
2441610c32b2SHoratiu Vultur if (err)
2442610c32b2SHoratiu Vultur return ERR_PTR(err);
24439579e2c2SSteen Hegelund
24441972b6d9SSteen Hegelund elem = vcap_get_locked_rule(vctrl, id);
2445610c32b2SHoratiu Vultur if (!elem)
2446093db9cdSRuan Jinjie return ERR_PTR(-ENOENT);
24479579e2c2SSteen Hegelund
24489579e2c2SSteen Hegelund rule = vcap_decode_rule(elem);
2449610c32b2SHoratiu Vultur mutex_unlock(&elem->admin->lock);
24509579e2c2SSteen Hegelund return rule;
2451610c32b2SHoratiu Vultur }
2452610c32b2SHoratiu Vultur EXPORT_SYMBOL_GPL(vcap_get_rule);
2453610c32b2SHoratiu Vultur
24542662b3f9SHoratiu Vultur /* Update existing rule */
vcap_mod_rule(struct vcap_rule * rule)24552662b3f9SHoratiu Vultur int vcap_mod_rule(struct vcap_rule *rule)
24562662b3f9SHoratiu Vultur {
24572662b3f9SHoratiu Vultur struct vcap_rule_internal *ri = to_intrule(rule);
24582662b3f9SHoratiu Vultur struct vcap_counter ctr;
24592662b3f9SHoratiu Vultur int err;
24602662b3f9SHoratiu Vultur
24612662b3f9SHoratiu Vultur err = vcap_api_check(ri->vctrl);
24622662b3f9SHoratiu Vultur if (err)
24632662b3f9SHoratiu Vultur return err;
24642662b3f9SHoratiu Vultur
24651972b6d9SSteen Hegelund if (!vcap_get_locked_rule(ri->vctrl, ri->data.id))
24662662b3f9SHoratiu Vultur return -ENOENT;
24672662b3f9SHoratiu Vultur
2468814e7693SSteen Hegelund vcap_rule_set_state(ri);
2469814e7693SSteen Hegelund if (ri->state == VCAP_RS_DISABLED)
2470814e7693SSteen Hegelund goto out;
2471814e7693SSteen Hegelund
24722662b3f9SHoratiu Vultur /* Encode the bitstreams to the VCAP cache */
24732662b3f9SHoratiu Vultur vcap_erase_cache(ri);
24742662b3f9SHoratiu Vultur err = vcap_encode_rule(ri);
24752662b3f9SHoratiu Vultur if (err)
24762662b3f9SHoratiu Vultur goto out;
24772662b3f9SHoratiu Vultur
24782662b3f9SHoratiu Vultur err = vcap_write_rule(ri);
24792662b3f9SHoratiu Vultur if (err)
24802662b3f9SHoratiu Vultur goto out;
24812662b3f9SHoratiu Vultur
24822662b3f9SHoratiu Vultur memset(&ctr, 0, sizeof(ctr));
24832662b3f9SHoratiu Vultur err = vcap_write_counter(ri, &ctr);
24842662b3f9SHoratiu Vultur
24852662b3f9SHoratiu Vultur out:
24862662b3f9SHoratiu Vultur mutex_unlock(&ri->admin->lock);
24872662b3f9SHoratiu Vultur return err;
24882662b3f9SHoratiu Vultur }
24892662b3f9SHoratiu Vultur EXPORT_SYMBOL_GPL(vcap_mod_rule);
24902662b3f9SHoratiu Vultur
2491990e4839SSteen Hegelund /* Return the alignment offset for a new rule address */
vcap_valid_rule_move(struct vcap_rule_internal * el,int offset)2492990e4839SSteen Hegelund static int vcap_valid_rule_move(struct vcap_rule_internal *el, int offset)
2493990e4839SSteen Hegelund {
2494990e4839SSteen Hegelund return (el->addr + offset) % el->size;
2495990e4839SSteen Hegelund }
2496990e4839SSteen Hegelund
2497990e4839SSteen Hegelund /* Update the rule address with an offset */
vcap_adjust_rule_addr(struct vcap_rule_internal * el,int offset)2498990e4839SSteen Hegelund static void vcap_adjust_rule_addr(struct vcap_rule_internal *el, int offset)
2499990e4839SSteen Hegelund {
2500990e4839SSteen Hegelund el->addr += offset;
2501990e4839SSteen Hegelund }
2502990e4839SSteen Hegelund
2503990e4839SSteen Hegelund /* Rules needs to be moved to fill the gap of the deleted rule */
vcap_fill_rule_gap(struct vcap_rule_internal * ri)2504990e4839SSteen Hegelund static int vcap_fill_rule_gap(struct vcap_rule_internal *ri)
2505990e4839SSteen Hegelund {
2506990e4839SSteen Hegelund struct vcap_admin *admin = ri->admin;
2507990e4839SSteen Hegelund struct vcap_rule_internal *elem;
2508990e4839SSteen Hegelund struct vcap_rule_move move;
2509990e4839SSteen Hegelund int gap = 0, offset = 0;
2510990e4839SSteen Hegelund
2511990e4839SSteen Hegelund /* If the first rule is deleted: Move other rules to the top */
2512990e4839SSteen Hegelund if (list_is_first(&ri->list, &admin->rules))
2513990e4839SSteen Hegelund offset = admin->last_valid_addr + 1 - ri->addr - ri->size;
2514990e4839SSteen Hegelund
2515990e4839SSteen Hegelund /* Locate gaps between odd size rules and adjust the move */
2516990e4839SSteen Hegelund elem = ri;
2517990e4839SSteen Hegelund list_for_each_entry_continue(elem, &admin->rules, list)
2518990e4839SSteen Hegelund gap += vcap_valid_rule_move(elem, ri->size);
2519990e4839SSteen Hegelund
2520990e4839SSteen Hegelund /* Update the address in the remaining rules in the list */
2521990e4839SSteen Hegelund elem = ri;
2522990e4839SSteen Hegelund list_for_each_entry_continue(elem, &admin->rules, list)
2523990e4839SSteen Hegelund vcap_adjust_rule_addr(elem, ri->size + gap + offset);
2524990e4839SSteen Hegelund
2525990e4839SSteen Hegelund /* Update the move info */
2526990e4839SSteen Hegelund move.addr = admin->last_used_addr;
2527990e4839SSteen Hegelund move.count = ri->addr - admin->last_used_addr - gap;
2528990e4839SSteen Hegelund move.offset = -(ri->size + gap + offset);
2529990e4839SSteen Hegelund
2530990e4839SSteen Hegelund /* Do the actual move operation */
2531990e4839SSteen Hegelund vcap_move_rules(ri, &move);
2532990e4839SSteen Hegelund
2533990e4839SSteen Hegelund return gap + offset;
2534990e4839SSteen Hegelund }
2535990e4839SSteen Hegelund
2536c9da1ac1SSteen Hegelund /* Delete rule in a VCAP instance */
vcap_del_rule(struct vcap_control * vctrl,struct net_device * ndev,u32 id)2537c9da1ac1SSteen Hegelund int vcap_del_rule(struct vcap_control *vctrl, struct net_device *ndev, u32 id)
2538c9da1ac1SSteen Hegelund {
2539c9da1ac1SSteen Hegelund struct vcap_rule_internal *ri, *elem;
2540c9da1ac1SSteen Hegelund struct vcap_admin *admin;
2541990e4839SSteen Hegelund int gap = 0, err;
2542c9da1ac1SSteen Hegelund
2543c9da1ac1SSteen Hegelund /* This will later also handle rule moving */
2544c9da1ac1SSteen Hegelund if (!ndev)
2545c9da1ac1SSteen Hegelund return -ENODEV;
25468e10490bSSteen Hegelund err = vcap_api_check(vctrl);
25478e10490bSSteen Hegelund if (err)
25488e10490bSSteen Hegelund return err;
2549c9da1ac1SSteen Hegelund /* Look for the rule id in all vcaps */
25501972b6d9SSteen Hegelund ri = vcap_get_locked_rule(vctrl, id);
2551c9da1ac1SSteen Hegelund if (!ri)
25521972b6d9SSteen Hegelund return -ENOENT;
25531972b6d9SSteen Hegelund
2554c9da1ac1SSteen Hegelund admin = ri->admin;
25558e10490bSSteen Hegelund
2556990e4839SSteen Hegelund if (ri->addr > admin->last_used_addr)
2557990e4839SSteen Hegelund gap = vcap_fill_rule_gap(ri);
2558990e4839SSteen Hegelund
2559990e4839SSteen Hegelund /* Delete the rule from the list of rules and the cache */
2560990e4839SSteen Hegelund list_del(&ri->list);
2561990e4839SSteen Hegelund vctrl->ops->init(ndev, admin, admin->last_used_addr, ri->size + gap);
2562814e7693SSteen Hegelund vcap_free_rule(&ri->data);
2563990e4839SSteen Hegelund
2564277e9179SSteen Hegelund /* Update the last used address, set to default when no rules */
2565c9da1ac1SSteen Hegelund if (list_empty(&admin->rules)) {
2566277e9179SSteen Hegelund admin->last_used_addr = admin->last_valid_addr + 1;
2567c9da1ac1SSteen Hegelund } else {
2568990e4839SSteen Hegelund elem = list_last_entry(&admin->rules, struct vcap_rule_internal,
2569990e4839SSteen Hegelund list);
2570c9da1ac1SSteen Hegelund admin->last_used_addr = elem->addr;
2571c9da1ac1SSteen Hegelund }
25721972b6d9SSteen Hegelund
25731972b6d9SSteen Hegelund mutex_unlock(&admin->lock);
25741972b6d9SSteen Hegelund return err;
2575c9da1ac1SSteen Hegelund }
2576c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_del_rule);
2577c9da1ac1SSteen Hegelund
25788e10490bSSteen Hegelund /* Delete all rules in the VCAP instance */
vcap_del_rules(struct vcap_control * vctrl,struct vcap_admin * admin)25798e10490bSSteen Hegelund int vcap_del_rules(struct vcap_control *vctrl, struct vcap_admin *admin)
25808e10490bSSteen Hegelund {
258167456717SSteen Hegelund struct vcap_enabled_port *eport, *next_eport;
25828e10490bSSteen Hegelund struct vcap_rule_internal *ri, *next_ri;
25838e10490bSSteen Hegelund int ret = vcap_api_check(vctrl);
25848e10490bSSteen Hegelund
25858e10490bSSteen Hegelund if (ret)
25868e10490bSSteen Hegelund return ret;
258771c9de99SSteen Hegelund
258871c9de99SSteen Hegelund mutex_lock(&admin->lock);
25898e10490bSSteen Hegelund list_for_each_entry_safe(ri, next_ri, &admin->rules, list) {
25908e10490bSSteen Hegelund vctrl->ops->init(ri->ndev, admin, ri->addr, ri->size);
25918e10490bSSteen Hegelund list_del(&ri->list);
2592814e7693SSteen Hegelund vcap_free_rule(&ri->data);
25938e10490bSSteen Hegelund }
25948e10490bSSteen Hegelund admin->last_used_addr = admin->last_valid_addr;
259567456717SSteen Hegelund
259667456717SSteen Hegelund /* Remove list of enabled ports */
259767456717SSteen Hegelund list_for_each_entry_safe(eport, next_eport, &admin->enabled, list) {
259867456717SSteen Hegelund list_del(&eport->list);
259967456717SSteen Hegelund kfree(eport);
260067456717SSteen Hegelund }
260171c9de99SSteen Hegelund mutex_unlock(&admin->lock);
260267456717SSteen Hegelund
26038e10490bSSteen Hegelund return 0;
26048e10490bSSteen Hegelund }
26058e10490bSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_del_rules);
26068e10490bSSteen Hegelund
2607465a38a2SSteen Hegelund /* Find a client key field in a rule */
2608465a38a2SSteen Hegelund static struct vcap_client_keyfield *
vcap_find_keyfield(struct vcap_rule * rule,enum vcap_key_field key)2609465a38a2SSteen Hegelund vcap_find_keyfield(struct vcap_rule *rule, enum vcap_key_field key)
2610465a38a2SSteen Hegelund {
2611465a38a2SSteen Hegelund struct vcap_rule_internal *ri = to_intrule(rule);
2612465a38a2SSteen Hegelund struct vcap_client_keyfield *ckf;
2613465a38a2SSteen Hegelund
2614465a38a2SSteen Hegelund list_for_each_entry(ckf, &ri->data.keyfields, ctrl.list)
2615465a38a2SSteen Hegelund if (ckf->ctrl.key == key)
2616465a38a2SSteen Hegelund return ckf;
2617465a38a2SSteen Hegelund return NULL;
2618465a38a2SSteen Hegelund }
2619465a38a2SSteen Hegelund
262046be056eSSteen Hegelund /* Find information on a key field in a rule */
vcap_lookup_keyfield(struct vcap_rule * rule,enum vcap_key_field key)262146be056eSSteen Hegelund const struct vcap_field *vcap_lookup_keyfield(struct vcap_rule *rule,
262246be056eSSteen Hegelund enum vcap_key_field key)
262346be056eSSteen Hegelund {
26248e10490bSSteen Hegelund struct vcap_rule_internal *ri = to_intrule(rule);
262546be056eSSteen Hegelund enum vcap_keyfield_set keyset = rule->keyset;
262646be056eSSteen Hegelund enum vcap_type vt = ri->admin->vtype;
262746be056eSSteen Hegelund const struct vcap_field *fields;
262846be056eSSteen Hegelund
262946be056eSSteen Hegelund if (keyset == VCAP_KFS_NO_VALUE)
263046be056eSSteen Hegelund return NULL;
263146be056eSSteen Hegelund fields = vcap_keyfields(ri->vctrl, vt, keyset);
263246be056eSSteen Hegelund if (!fields)
263346be056eSSteen Hegelund return NULL;
263446be056eSSteen Hegelund return &fields[key];
263546be056eSSteen Hegelund }
263646be056eSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_lookup_keyfield);
263746be056eSSteen Hegelund
2638242df4f7SSteen Hegelund /* Check if the keyfield is already in the rule */
vcap_keyfield_unique(struct vcap_rule * rule,enum vcap_key_field key)2639242df4f7SSteen Hegelund static bool vcap_keyfield_unique(struct vcap_rule *rule,
2640242df4f7SSteen Hegelund enum vcap_key_field key)
2641242df4f7SSteen Hegelund {
2642242df4f7SSteen Hegelund struct vcap_rule_internal *ri = to_intrule(rule);
2643242df4f7SSteen Hegelund const struct vcap_client_keyfield *ckf;
2644242df4f7SSteen Hegelund
2645242df4f7SSteen Hegelund list_for_each_entry(ckf, &ri->data.keyfields, ctrl.list)
2646242df4f7SSteen Hegelund if (ckf->ctrl.key == key)
2647242df4f7SSteen Hegelund return false;
2648242df4f7SSteen Hegelund return true;
2649242df4f7SSteen Hegelund }
2650242df4f7SSteen Hegelund
2651242df4f7SSteen Hegelund /* Check if the keyfield is in the keyset */
vcap_keyfield_match_keyset(struct vcap_rule * rule,enum vcap_key_field key)2652242df4f7SSteen Hegelund static bool vcap_keyfield_match_keyset(struct vcap_rule *rule,
2653242df4f7SSteen Hegelund enum vcap_key_field key)
2654242df4f7SSteen Hegelund {
2655242df4f7SSteen Hegelund struct vcap_rule_internal *ri = to_intrule(rule);
2656242df4f7SSteen Hegelund enum vcap_keyfield_set keyset = rule->keyset;
2657242df4f7SSteen Hegelund enum vcap_type vt = ri->admin->vtype;
2658242df4f7SSteen Hegelund const struct vcap_field *fields;
2659242df4f7SSteen Hegelund
2660242df4f7SSteen Hegelund /* the field is accepted if the rule has no keyset yet */
2661242df4f7SSteen Hegelund if (keyset == VCAP_KFS_NO_VALUE)
2662242df4f7SSteen Hegelund return true;
2663242df4f7SSteen Hegelund fields = vcap_keyfields(ri->vctrl, vt, keyset);
2664242df4f7SSteen Hegelund if (!fields)
2665242df4f7SSteen Hegelund return false;
2666242df4f7SSteen Hegelund /* if there is a width there is a way */
2667242df4f7SSteen Hegelund return fields[key].width > 0;
2668242df4f7SSteen Hegelund }
2669242df4f7SSteen Hegelund
vcap_rule_add_key(struct vcap_rule * rule,enum vcap_key_field key,enum vcap_field_type ftype,struct vcap_client_keyfield_data * data)2670c9da1ac1SSteen Hegelund static int vcap_rule_add_key(struct vcap_rule *rule,
2671c9da1ac1SSteen Hegelund enum vcap_key_field key,
2672c9da1ac1SSteen Hegelund enum vcap_field_type ftype,
2673c9da1ac1SSteen Hegelund struct vcap_client_keyfield_data *data)
2674c9da1ac1SSteen Hegelund {
2675242df4f7SSteen Hegelund struct vcap_rule_internal *ri = to_intrule(rule);
2676c9da1ac1SSteen Hegelund struct vcap_client_keyfield *field;
2677c9da1ac1SSteen Hegelund
2678242df4f7SSteen Hegelund if (!vcap_keyfield_unique(rule, key)) {
2679242df4f7SSteen Hegelund pr_warn("%s:%d: keyfield %s is already in the rule\n",
2680242df4f7SSteen Hegelund __func__, __LINE__,
2681242df4f7SSteen Hegelund vcap_keyfield_name(ri->vctrl, key));
2682242df4f7SSteen Hegelund return -EINVAL;
2683242df4f7SSteen Hegelund }
2684242df4f7SSteen Hegelund
2685242df4f7SSteen Hegelund if (!vcap_keyfield_match_keyset(rule, key)) {
2686242df4f7SSteen Hegelund pr_err("%s:%d: keyfield %s does not belong in the rule keyset\n",
2687242df4f7SSteen Hegelund __func__, __LINE__,
2688242df4f7SSteen Hegelund vcap_keyfield_name(ri->vctrl, key));
2689242df4f7SSteen Hegelund return -EINVAL;
2690242df4f7SSteen Hegelund }
2691242df4f7SSteen Hegelund
2692c9da1ac1SSteen Hegelund field = kzalloc(sizeof(*field), GFP_KERNEL);
2693c9da1ac1SSteen Hegelund if (!field)
2694c9da1ac1SSteen Hegelund return -ENOMEM;
269533e3a273SSteen Hegelund memcpy(&field->data, data, sizeof(field->data));
2696c9da1ac1SSteen Hegelund field->ctrl.key = key;
2697c9da1ac1SSteen Hegelund field->ctrl.type = ftype;
2698c9da1ac1SSteen Hegelund list_add_tail(&field->ctrl.list, &rule->keyfields);
2699c9da1ac1SSteen Hegelund return 0;
2700c9da1ac1SSteen Hegelund }
2701c9da1ac1SSteen Hegelund
vcap_rule_set_key_bitsize(struct vcap_u1_key * u1,enum vcap_bit val)270246be056eSSteen Hegelund static void vcap_rule_set_key_bitsize(struct vcap_u1_key *u1, enum vcap_bit val)
270346be056eSSteen Hegelund {
270446be056eSSteen Hegelund switch (val) {
270546be056eSSteen Hegelund case VCAP_BIT_0:
270646be056eSSteen Hegelund u1->value = 0;
270746be056eSSteen Hegelund u1->mask = 1;
270846be056eSSteen Hegelund break;
270946be056eSSteen Hegelund case VCAP_BIT_1:
271046be056eSSteen Hegelund u1->value = 1;
271146be056eSSteen Hegelund u1->mask = 1;
271246be056eSSteen Hegelund break;
271346be056eSSteen Hegelund case VCAP_BIT_ANY:
271446be056eSSteen Hegelund u1->value = 0;
271546be056eSSteen Hegelund u1->mask = 0;
271646be056eSSteen Hegelund break;
271746be056eSSteen Hegelund }
271846be056eSSteen Hegelund }
271946be056eSSteen Hegelund
272046be056eSSteen Hegelund /* Add a bit key with value and mask to the rule */
vcap_rule_add_key_bit(struct vcap_rule * rule,enum vcap_key_field key,enum vcap_bit val)272146be056eSSteen Hegelund int vcap_rule_add_key_bit(struct vcap_rule *rule, enum vcap_key_field key,
272246be056eSSteen Hegelund enum vcap_bit val)
272346be056eSSteen Hegelund {
272446be056eSSteen Hegelund struct vcap_client_keyfield_data data;
272546be056eSSteen Hegelund
272646be056eSSteen Hegelund vcap_rule_set_key_bitsize(&data.u1, val);
272746be056eSSteen Hegelund return vcap_rule_add_key(rule, key, VCAP_FIELD_BIT, &data);
272846be056eSSteen Hegelund }
272946be056eSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_add_key_bit);
273046be056eSSteen Hegelund
273146be056eSSteen Hegelund /* Add a 32 bit key field with value and mask to the rule */
vcap_rule_add_key_u32(struct vcap_rule * rule,enum vcap_key_field key,u32 value,u32 mask)273246be056eSSteen Hegelund int vcap_rule_add_key_u32(struct vcap_rule *rule, enum vcap_key_field key,
273346be056eSSteen Hegelund u32 value, u32 mask)
273446be056eSSteen Hegelund {
273546be056eSSteen Hegelund struct vcap_client_keyfield_data data;
273646be056eSSteen Hegelund
273746be056eSSteen Hegelund data.u32.value = value;
273846be056eSSteen Hegelund data.u32.mask = mask;
273946be056eSSteen Hegelund return vcap_rule_add_key(rule, key, VCAP_FIELD_U32, &data);
274046be056eSSteen Hegelund }
274146be056eSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_add_key_u32);
274246be056eSSteen Hegelund
2743c9da1ac1SSteen Hegelund /* Add a 48 bit key with value and mask to the rule */
vcap_rule_add_key_u48(struct vcap_rule * rule,enum vcap_key_field key,struct vcap_u48_key * fieldval)2744c9da1ac1SSteen Hegelund int vcap_rule_add_key_u48(struct vcap_rule *rule, enum vcap_key_field key,
2745c9da1ac1SSteen Hegelund struct vcap_u48_key *fieldval)
2746c9da1ac1SSteen Hegelund {
2747c9da1ac1SSteen Hegelund struct vcap_client_keyfield_data data;
2748c9da1ac1SSteen Hegelund
2749c9da1ac1SSteen Hegelund memcpy(&data.u48, fieldval, sizeof(data.u48));
2750c9da1ac1SSteen Hegelund return vcap_rule_add_key(rule, key, VCAP_FIELD_U48, &data);
2751c9da1ac1SSteen Hegelund }
2752c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_add_key_u48);
2753c9da1ac1SSteen Hegelund
275446be056eSSteen Hegelund /* Add a 72 bit key with value and mask to the rule */
vcap_rule_add_key_u72(struct vcap_rule * rule,enum vcap_key_field key,struct vcap_u72_key * fieldval)275546be056eSSteen Hegelund int vcap_rule_add_key_u72(struct vcap_rule *rule, enum vcap_key_field key,
275646be056eSSteen Hegelund struct vcap_u72_key *fieldval)
275746be056eSSteen Hegelund {
275846be056eSSteen Hegelund struct vcap_client_keyfield_data data;
275946be056eSSteen Hegelund
276046be056eSSteen Hegelund memcpy(&data.u72, fieldval, sizeof(data.u72));
276146be056eSSteen Hegelund return vcap_rule_add_key(rule, key, VCAP_FIELD_U72, &data);
276246be056eSSteen Hegelund }
276346be056eSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_add_key_u72);
276446be056eSSteen Hegelund
2765d6c2964dSSteen Hegelund /* Add a 128 bit key with value and mask to the rule */
vcap_rule_add_key_u128(struct vcap_rule * rule,enum vcap_key_field key,struct vcap_u128_key * fieldval)2766d6c2964dSSteen Hegelund int vcap_rule_add_key_u128(struct vcap_rule *rule, enum vcap_key_field key,
2767d6c2964dSSteen Hegelund struct vcap_u128_key *fieldval)
2768d6c2964dSSteen Hegelund {
2769d6c2964dSSteen Hegelund struct vcap_client_keyfield_data data;
2770d6c2964dSSteen Hegelund
2771d6c2964dSSteen Hegelund memcpy(&data.u128, fieldval, sizeof(data.u128));
2772d6c2964dSSteen Hegelund return vcap_rule_add_key(rule, key, VCAP_FIELD_U128, &data);
2773d6c2964dSSteen Hegelund }
2774d6c2964dSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_add_key_u128);
2775d6c2964dSSteen Hegelund
vcap_rule_get_key_u32(struct vcap_rule * rule,enum vcap_key_field key,u32 * value,u32 * mask)27766009b61fSHoratiu Vultur int vcap_rule_get_key_u32(struct vcap_rule *rule, enum vcap_key_field key,
27776009b61fSHoratiu Vultur u32 *value, u32 *mask)
27786009b61fSHoratiu Vultur {
27796009b61fSHoratiu Vultur struct vcap_client_keyfield *ckf;
27806009b61fSHoratiu Vultur
27816009b61fSHoratiu Vultur ckf = vcap_find_keyfield(rule, key);
27826009b61fSHoratiu Vultur if (!ckf)
27836009b61fSHoratiu Vultur return -ENOENT;
27846009b61fSHoratiu Vultur
27856009b61fSHoratiu Vultur *value = ckf->data.u32.value;
27866009b61fSHoratiu Vultur *mask = ckf->data.u32.mask;
27876009b61fSHoratiu Vultur
27886009b61fSHoratiu Vultur return 0;
27896009b61fSHoratiu Vultur }
27906009b61fSHoratiu Vultur EXPORT_SYMBOL_GPL(vcap_rule_get_key_u32);
27916009b61fSHoratiu Vultur
2792465a38a2SSteen Hegelund /* Find a client action field in a rule */
27936ebf182bSDaniel Machon struct vcap_client_actionfield *
vcap_find_actionfield(struct vcap_rule * rule,enum vcap_action_field act)2794465a38a2SSteen Hegelund vcap_find_actionfield(struct vcap_rule *rule, enum vcap_action_field act)
2795465a38a2SSteen Hegelund {
2796465a38a2SSteen Hegelund struct vcap_rule_internal *ri = (struct vcap_rule_internal *)rule;
2797465a38a2SSteen Hegelund struct vcap_client_actionfield *caf;
2798465a38a2SSteen Hegelund
2799465a38a2SSteen Hegelund list_for_each_entry(caf, &ri->data.actionfields, ctrl.list)
2800465a38a2SSteen Hegelund if (caf->ctrl.action == act)
2801465a38a2SSteen Hegelund return caf;
2802465a38a2SSteen Hegelund return NULL;
2803465a38a2SSteen Hegelund }
28046ebf182bSDaniel Machon EXPORT_SYMBOL_GPL(vcap_find_actionfield);
2805465a38a2SSteen Hegelund
2806242df4f7SSteen Hegelund /* Check if the actionfield is already in the rule */
vcap_actionfield_unique(struct vcap_rule * rule,enum vcap_action_field act)2807242df4f7SSteen Hegelund static bool vcap_actionfield_unique(struct vcap_rule *rule,
2808242df4f7SSteen Hegelund enum vcap_action_field act)
2809242df4f7SSteen Hegelund {
2810242df4f7SSteen Hegelund struct vcap_rule_internal *ri = to_intrule(rule);
2811242df4f7SSteen Hegelund const struct vcap_client_actionfield *caf;
2812242df4f7SSteen Hegelund
2813242df4f7SSteen Hegelund list_for_each_entry(caf, &ri->data.actionfields, ctrl.list)
2814242df4f7SSteen Hegelund if (caf->ctrl.action == act)
2815242df4f7SSteen Hegelund return false;
2816242df4f7SSteen Hegelund return true;
2817242df4f7SSteen Hegelund }
2818242df4f7SSteen Hegelund
2819242df4f7SSteen Hegelund /* Check if the actionfield is in the actionset */
vcap_actionfield_match_actionset(struct vcap_rule * rule,enum vcap_action_field action)2820242df4f7SSteen Hegelund static bool vcap_actionfield_match_actionset(struct vcap_rule *rule,
2821242df4f7SSteen Hegelund enum vcap_action_field action)
2822242df4f7SSteen Hegelund {
2823242df4f7SSteen Hegelund enum vcap_actionfield_set actionset = rule->actionset;
2824242df4f7SSteen Hegelund struct vcap_rule_internal *ri = to_intrule(rule);
2825242df4f7SSteen Hegelund enum vcap_type vt = ri->admin->vtype;
2826242df4f7SSteen Hegelund const struct vcap_field *fields;
2827242df4f7SSteen Hegelund
2828242df4f7SSteen Hegelund /* the field is accepted if the rule has no actionset yet */
2829242df4f7SSteen Hegelund if (actionset == VCAP_AFS_NO_VALUE)
2830242df4f7SSteen Hegelund return true;
2831242df4f7SSteen Hegelund fields = vcap_actionfields(ri->vctrl, vt, actionset);
2832242df4f7SSteen Hegelund if (!fields)
2833242df4f7SSteen Hegelund return false;
2834242df4f7SSteen Hegelund /* if there is a width there is a way */
2835242df4f7SSteen Hegelund return fields[action].width > 0;
2836242df4f7SSteen Hegelund }
2837242df4f7SSteen Hegelund
vcap_rule_add_action(struct vcap_rule * rule,enum vcap_action_field action,enum vcap_field_type ftype,struct vcap_client_actionfield_data * data)2838c9da1ac1SSteen Hegelund static int vcap_rule_add_action(struct vcap_rule *rule,
2839c9da1ac1SSteen Hegelund enum vcap_action_field action,
2840c9da1ac1SSteen Hegelund enum vcap_field_type ftype,
2841c9da1ac1SSteen Hegelund struct vcap_client_actionfield_data *data)
2842c9da1ac1SSteen Hegelund {
2843242df4f7SSteen Hegelund struct vcap_rule_internal *ri = to_intrule(rule);
2844c9da1ac1SSteen Hegelund struct vcap_client_actionfield *field;
2845c9da1ac1SSteen Hegelund
2846242df4f7SSteen Hegelund if (!vcap_actionfield_unique(rule, action)) {
2847242df4f7SSteen Hegelund pr_warn("%s:%d: actionfield %s is already in the rule\n",
2848242df4f7SSteen Hegelund __func__, __LINE__,
2849242df4f7SSteen Hegelund vcap_actionfield_name(ri->vctrl, action));
2850242df4f7SSteen Hegelund return -EINVAL;
2851242df4f7SSteen Hegelund }
2852242df4f7SSteen Hegelund
2853242df4f7SSteen Hegelund if (!vcap_actionfield_match_actionset(rule, action)) {
2854242df4f7SSteen Hegelund pr_err("%s:%d: actionfield %s does not belong in the rule actionset\n",
2855242df4f7SSteen Hegelund __func__, __LINE__,
2856242df4f7SSteen Hegelund vcap_actionfield_name(ri->vctrl, action));
2857242df4f7SSteen Hegelund return -EINVAL;
2858242df4f7SSteen Hegelund }
2859242df4f7SSteen Hegelund
2860c9da1ac1SSteen Hegelund field = kzalloc(sizeof(*field), GFP_KERNEL);
2861c9da1ac1SSteen Hegelund if (!field)
2862c9da1ac1SSteen Hegelund return -ENOMEM;
286333e3a273SSteen Hegelund memcpy(&field->data, data, sizeof(field->data));
2864c9da1ac1SSteen Hegelund field->ctrl.action = action;
2865c9da1ac1SSteen Hegelund field->ctrl.type = ftype;
2866c9da1ac1SSteen Hegelund list_add_tail(&field->ctrl.list, &rule->actionfields);
2867c9da1ac1SSteen Hegelund return 0;
2868c9da1ac1SSteen Hegelund }
2869c9da1ac1SSteen Hegelund
vcap_rule_set_action_bitsize(struct vcap_u1_action * u1,enum vcap_bit val)2870c9da1ac1SSteen Hegelund static void vcap_rule_set_action_bitsize(struct vcap_u1_action *u1,
2871c9da1ac1SSteen Hegelund enum vcap_bit val)
2872c9da1ac1SSteen Hegelund {
2873c9da1ac1SSteen Hegelund switch (val) {
2874c9da1ac1SSteen Hegelund case VCAP_BIT_0:
2875c9da1ac1SSteen Hegelund u1->value = 0;
2876c9da1ac1SSteen Hegelund break;
2877c9da1ac1SSteen Hegelund case VCAP_BIT_1:
2878c9da1ac1SSteen Hegelund u1->value = 1;
2879c9da1ac1SSteen Hegelund break;
2880c9da1ac1SSteen Hegelund case VCAP_BIT_ANY:
2881c9da1ac1SSteen Hegelund u1->value = 0;
2882c9da1ac1SSteen Hegelund break;
2883c9da1ac1SSteen Hegelund }
2884c9da1ac1SSteen Hegelund }
2885c9da1ac1SSteen Hegelund
2886c9da1ac1SSteen Hegelund /* Add a bit action with value to the rule */
vcap_rule_add_action_bit(struct vcap_rule * rule,enum vcap_action_field action,enum vcap_bit val)2887c9da1ac1SSteen Hegelund int vcap_rule_add_action_bit(struct vcap_rule *rule,
2888c9da1ac1SSteen Hegelund enum vcap_action_field action,
2889c9da1ac1SSteen Hegelund enum vcap_bit val)
2890c9da1ac1SSteen Hegelund {
2891c9da1ac1SSteen Hegelund struct vcap_client_actionfield_data data;
2892c9da1ac1SSteen Hegelund
2893c9da1ac1SSteen Hegelund vcap_rule_set_action_bitsize(&data.u1, val);
2894c9da1ac1SSteen Hegelund return vcap_rule_add_action(rule, action, VCAP_FIELD_BIT, &data);
2895c9da1ac1SSteen Hegelund }
2896c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_add_action_bit);
2897c9da1ac1SSteen Hegelund
2898c9da1ac1SSteen Hegelund /* Add a 32 bit action field with value to the rule */
vcap_rule_add_action_u32(struct vcap_rule * rule,enum vcap_action_field action,u32 value)2899c9da1ac1SSteen Hegelund int vcap_rule_add_action_u32(struct vcap_rule *rule,
2900c9da1ac1SSteen Hegelund enum vcap_action_field action,
2901c9da1ac1SSteen Hegelund u32 value)
2902c9da1ac1SSteen Hegelund {
2903c9da1ac1SSteen Hegelund struct vcap_client_actionfield_data data;
2904c9da1ac1SSteen Hegelund
2905c9da1ac1SSteen Hegelund data.u32.value = value;
2906c9da1ac1SSteen Hegelund return vcap_rule_add_action(rule, action, VCAP_FIELD_U32, &data);
2907c9da1ac1SSteen Hegelund }
2908c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_add_action_u32);
2909c9da1ac1SSteen Hegelund
291048ba00daSDaniel Machon /* Add a 72 bit action field with value to the rule */
vcap_rule_add_action_u72(struct vcap_rule * rule,enum vcap_action_field action,struct vcap_u72_action * fieldval)291148ba00daSDaniel Machon int vcap_rule_add_action_u72(struct vcap_rule *rule,
291248ba00daSDaniel Machon enum vcap_action_field action,
291348ba00daSDaniel Machon struct vcap_u72_action *fieldval)
291448ba00daSDaniel Machon {
291548ba00daSDaniel Machon struct vcap_client_actionfield_data data;
291648ba00daSDaniel Machon
291748ba00daSDaniel Machon memcpy(&data.u72, fieldval, sizeof(data.u72));
291848ba00daSDaniel Machon return vcap_rule_add_action(rule, action, VCAP_FIELD_U72, &data);
291948ba00daSDaniel Machon }
292048ba00daSDaniel Machon EXPORT_SYMBOL_GPL(vcap_rule_add_action_u72);
292148ba00daSDaniel Machon
vcap_read_counter(struct vcap_rule_internal * ri,struct vcap_counter * ctr)2922f13230a4SSteen Hegelund static int vcap_read_counter(struct vcap_rule_internal *ri,
2923f13230a4SSteen Hegelund struct vcap_counter *ctr)
2924f13230a4SSteen Hegelund {
2925f13230a4SSteen Hegelund struct vcap_admin *admin = ri->admin;
2926f13230a4SSteen Hegelund
2927f13230a4SSteen Hegelund ri->vctrl->ops->update(ri->ndev, admin, VCAP_CMD_READ, VCAP_SEL_COUNTER,
2928f13230a4SSteen Hegelund ri->addr);
2929f13230a4SSteen Hegelund ri->vctrl->ops->cache_read(ri->ndev, admin, VCAP_SEL_COUNTER,
2930f13230a4SSteen Hegelund ri->counter_id, 0);
2931f13230a4SSteen Hegelund ctr->value = admin->cache.counter;
2932f13230a4SSteen Hegelund ctr->sticky = admin->cache.sticky;
2933f13230a4SSteen Hegelund return 0;
2934f13230a4SSteen Hegelund }
2935f13230a4SSteen Hegelund
2936c9da1ac1SSteen Hegelund /* Copy to host byte order */
vcap_netbytes_copy(u8 * dst,u8 * src,int count)2937c9da1ac1SSteen Hegelund void vcap_netbytes_copy(u8 *dst, u8 *src, int count)
2938c9da1ac1SSteen Hegelund {
2939c9da1ac1SSteen Hegelund int idx;
2940c9da1ac1SSteen Hegelund
2941c9da1ac1SSteen Hegelund for (idx = 0; idx < count; ++idx, ++dst)
2942c9da1ac1SSteen Hegelund *dst = src[count - idx - 1];
2943c9da1ac1SSteen Hegelund }
2944c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_netbytes_copy);
2945c9da1ac1SSteen Hegelund
2946*d896a374SSimon Horman /* Convert validation error code into tc extack error message */
vcap_set_tc_exterr(struct flow_cls_offload * fco,struct vcap_rule * vrule)2947c9da1ac1SSteen Hegelund void vcap_set_tc_exterr(struct flow_cls_offload *fco, struct vcap_rule *vrule)
2948c9da1ac1SSteen Hegelund {
2949c9da1ac1SSteen Hegelund switch (vrule->exterr) {
2950c9da1ac1SSteen Hegelund case VCAP_ERR_NONE:
2951c9da1ac1SSteen Hegelund break;
2952c9da1ac1SSteen Hegelund case VCAP_ERR_NO_ADMIN:
2953c9da1ac1SSteen Hegelund NL_SET_ERR_MSG_MOD(fco->common.extack,
2954c9da1ac1SSteen Hegelund "Missing VCAP instance");
2955c9da1ac1SSteen Hegelund break;
2956c9da1ac1SSteen Hegelund case VCAP_ERR_NO_NETDEV:
2957c9da1ac1SSteen Hegelund NL_SET_ERR_MSG_MOD(fco->common.extack,
2958c9da1ac1SSteen Hegelund "Missing network interface");
2959c9da1ac1SSteen Hegelund break;
2960c9da1ac1SSteen Hegelund case VCAP_ERR_NO_KEYSET_MATCH:
2961c9da1ac1SSteen Hegelund NL_SET_ERR_MSG_MOD(fco->common.extack,
2962c9da1ac1SSteen Hegelund "No keyset matched the filter keys");
2963c9da1ac1SSteen Hegelund break;
2964c9da1ac1SSteen Hegelund case VCAP_ERR_NO_ACTIONSET_MATCH:
2965c9da1ac1SSteen Hegelund NL_SET_ERR_MSG_MOD(fco->common.extack,
2966c9da1ac1SSteen Hegelund "No actionset matched the filter actions");
2967c9da1ac1SSteen Hegelund break;
2968c9da1ac1SSteen Hegelund case VCAP_ERR_NO_PORT_KEYSET_MATCH:
2969c9da1ac1SSteen Hegelund NL_SET_ERR_MSG_MOD(fco->common.extack,
2970c9da1ac1SSteen Hegelund "No port keyset matched the filter keys");
2971c9da1ac1SSteen Hegelund break;
2972c9da1ac1SSteen Hegelund }
2973c9da1ac1SSteen Hegelund }
2974c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_set_tc_exterr);
297567d63751SSteen Hegelund
297618a15c76SSteen Hegelund /* Write a rule to VCAP HW to enable it */
vcap_enable_rule(struct vcap_rule_internal * ri)297718a15c76SSteen Hegelund static int vcap_enable_rule(struct vcap_rule_internal *ri)
297818a15c76SSteen Hegelund {
297918a15c76SSteen Hegelund struct vcap_client_actionfield *af, *naf;
298018a15c76SSteen Hegelund struct vcap_client_keyfield *kf, *nkf;
298118a15c76SSteen Hegelund int err;
298218a15c76SSteen Hegelund
298318a15c76SSteen Hegelund vcap_erase_cache(ri);
298418a15c76SSteen Hegelund err = vcap_encode_rule(ri);
298518a15c76SSteen Hegelund if (err)
298618a15c76SSteen Hegelund goto out;
298718a15c76SSteen Hegelund err = vcap_write_rule(ri);
298818a15c76SSteen Hegelund if (err)
298918a15c76SSteen Hegelund goto out;
299018a15c76SSteen Hegelund
299118a15c76SSteen Hegelund /* Deallocate the list of keys and actions */
299218a15c76SSteen Hegelund list_for_each_entry_safe(kf, nkf, &ri->data.keyfields, ctrl.list) {
299318a15c76SSteen Hegelund list_del(&kf->ctrl.list);
299418a15c76SSteen Hegelund kfree(kf);
299518a15c76SSteen Hegelund }
299618a15c76SSteen Hegelund list_for_each_entry_safe(af, naf, &ri->data.actionfields, ctrl.list) {
299718a15c76SSteen Hegelund list_del(&af->ctrl.list);
299818a15c76SSteen Hegelund kfree(af);
299918a15c76SSteen Hegelund }
300018a15c76SSteen Hegelund ri->state = VCAP_RS_ENABLED;
300118a15c76SSteen Hegelund out:
300218a15c76SSteen Hegelund return err;
300318a15c76SSteen Hegelund }
300418a15c76SSteen Hegelund
300518a15c76SSteen Hegelund /* Enable all disabled rules for a specific chain/port in the VCAP HW */
vcap_enable_rules(struct vcap_control * vctrl,struct net_device * ndev,int chain)300618a15c76SSteen Hegelund static int vcap_enable_rules(struct vcap_control *vctrl,
300718a15c76SSteen Hegelund struct net_device *ndev, int chain)
300818a15c76SSteen Hegelund {
300988bd9ea7SSteen Hegelund int next_chain = chain + VCAP_CID_LOOKUP_SIZE;
301018a15c76SSteen Hegelund struct vcap_rule_internal *ri;
301118a15c76SSteen Hegelund struct vcap_admin *admin;
301218a15c76SSteen Hegelund int err = 0;
301318a15c76SSteen Hegelund
301418a15c76SSteen Hegelund list_for_each_entry(admin, &vctrl->list, list) {
301518a15c76SSteen Hegelund if (!(chain >= admin->first_cid && chain <= admin->last_cid))
301618a15c76SSteen Hegelund continue;
301718a15c76SSteen Hegelund
301818a15c76SSteen Hegelund /* Found the admin, now find the offloadable rules */
301918a15c76SSteen Hegelund mutex_lock(&admin->lock);
302018a15c76SSteen Hegelund list_for_each_entry(ri, &admin->rules, list) {
302188bd9ea7SSteen Hegelund /* Is the rule in the lookup defined by the chain */
302288bd9ea7SSteen Hegelund if (!(ri->data.vcap_chain_id >= chain &&
302388bd9ea7SSteen Hegelund ri->data.vcap_chain_id < next_chain)) {
302418a15c76SSteen Hegelund continue;
302588bd9ea7SSteen Hegelund }
302618a15c76SSteen Hegelund
302718a15c76SSteen Hegelund if (ri->ndev != ndev)
302818a15c76SSteen Hegelund continue;
302918a15c76SSteen Hegelund
303018a15c76SSteen Hegelund if (ri->state != VCAP_RS_DISABLED)
303118a15c76SSteen Hegelund continue;
303218a15c76SSteen Hegelund
303318a15c76SSteen Hegelund err = vcap_enable_rule(ri);
303418a15c76SSteen Hegelund if (err)
303518a15c76SSteen Hegelund break;
303618a15c76SSteen Hegelund }
303718a15c76SSteen Hegelund mutex_unlock(&admin->lock);
303818a15c76SSteen Hegelund if (err)
303918a15c76SSteen Hegelund break;
304018a15c76SSteen Hegelund }
304118a15c76SSteen Hegelund return err;
304218a15c76SSteen Hegelund }
304318a15c76SSteen Hegelund
304418a15c76SSteen Hegelund /* Read and erase a rule from VCAP HW to disable it */
vcap_disable_rule(struct vcap_rule_internal * ri)304518a15c76SSteen Hegelund static int vcap_disable_rule(struct vcap_rule_internal *ri)
304618a15c76SSteen Hegelund {
304718a15c76SSteen Hegelund int err;
304818a15c76SSteen Hegelund
304918a15c76SSteen Hegelund err = vcap_read_rule(ri);
305018a15c76SSteen Hegelund if (err)
305118a15c76SSteen Hegelund return err;
305218a15c76SSteen Hegelund err = vcap_decode_keyset(ri);
305318a15c76SSteen Hegelund if (err)
305418a15c76SSteen Hegelund return err;
305518a15c76SSteen Hegelund err = vcap_decode_actionset(ri);
305618a15c76SSteen Hegelund if (err)
305718a15c76SSteen Hegelund return err;
305818a15c76SSteen Hegelund
305918a15c76SSteen Hegelund ri->state = VCAP_RS_DISABLED;
306018a15c76SSteen Hegelund ri->vctrl->ops->init(ri->ndev, ri->admin, ri->addr, ri->size);
306118a15c76SSteen Hegelund return 0;
306218a15c76SSteen Hegelund }
306318a15c76SSteen Hegelund
306418a15c76SSteen Hegelund /* Disable all enabled rules for a specific chain/port in the VCAP HW */
vcap_disable_rules(struct vcap_control * vctrl,struct net_device * ndev,int chain)306518a15c76SSteen Hegelund static int vcap_disable_rules(struct vcap_control *vctrl,
306618a15c76SSteen Hegelund struct net_device *ndev, int chain)
306718a15c76SSteen Hegelund {
306818a15c76SSteen Hegelund struct vcap_rule_internal *ri;
306918a15c76SSteen Hegelund struct vcap_admin *admin;
307018a15c76SSteen Hegelund int err = 0;
307118a15c76SSteen Hegelund
307218a15c76SSteen Hegelund list_for_each_entry(admin, &vctrl->list, list) {
307318a15c76SSteen Hegelund if (!(chain >= admin->first_cid && chain <= admin->last_cid))
307418a15c76SSteen Hegelund continue;
307518a15c76SSteen Hegelund
307618a15c76SSteen Hegelund /* Found the admin, now find the rules on the chain */
307718a15c76SSteen Hegelund mutex_lock(&admin->lock);
307818a15c76SSteen Hegelund list_for_each_entry(ri, &admin->rules, list) {
307918a15c76SSteen Hegelund if (ri->data.vcap_chain_id != chain)
308018a15c76SSteen Hegelund continue;
308118a15c76SSteen Hegelund
308218a15c76SSteen Hegelund if (ri->ndev != ndev)
308318a15c76SSteen Hegelund continue;
308418a15c76SSteen Hegelund
308518a15c76SSteen Hegelund if (ri->state != VCAP_RS_ENABLED)
308618a15c76SSteen Hegelund continue;
308718a15c76SSteen Hegelund
308818a15c76SSteen Hegelund err = vcap_disable_rule(ri);
308918a15c76SSteen Hegelund if (err)
309018a15c76SSteen Hegelund break;
309118a15c76SSteen Hegelund }
309218a15c76SSteen Hegelund mutex_unlock(&admin->lock);
309318a15c76SSteen Hegelund if (err)
309418a15c76SSteen Hegelund break;
309518a15c76SSteen Hegelund }
309618a15c76SSteen Hegelund return err;
309718a15c76SSteen Hegelund }
309818a15c76SSteen Hegelund
309967456717SSteen Hegelund /* Check if this port is already enabled for this VCAP instance */
vcap_is_enabled(struct vcap_control * vctrl,struct net_device * ndev,int dst_cid)3100cfd9e7b7SSteen Hegelund static bool vcap_is_enabled(struct vcap_control *vctrl, struct net_device *ndev,
3101cfd9e7b7SSteen Hegelund int dst_cid)
310267456717SSteen Hegelund {
310367456717SSteen Hegelund struct vcap_enabled_port *eport;
3104cfd9e7b7SSteen Hegelund struct vcap_admin *admin;
310567456717SSteen Hegelund
3106cfd9e7b7SSteen Hegelund list_for_each_entry(admin, &vctrl->list, list)
310767456717SSteen Hegelund list_for_each_entry(eport, &admin->enabled, list)
3108cfd9e7b7SSteen Hegelund if (eport->dst_cid == dst_cid && eport->ndev == ndev)
310967456717SSteen Hegelund return true;
311067456717SSteen Hegelund
311167456717SSteen Hegelund return false;
311267456717SSteen Hegelund }
311367456717SSteen Hegelund
3114cfd9e7b7SSteen Hegelund /* Enable this port and chain id in a VCAP instance */
vcap_enable(struct vcap_control * vctrl,struct net_device * ndev,unsigned long cookie,int src_cid,int dst_cid)3115cfd9e7b7SSteen Hegelund static int vcap_enable(struct vcap_control *vctrl, struct net_device *ndev,
3116cfd9e7b7SSteen Hegelund unsigned long cookie, int src_cid, int dst_cid)
311767456717SSteen Hegelund {
311867456717SSteen Hegelund struct vcap_enabled_port *eport;
3119cfd9e7b7SSteen Hegelund struct vcap_admin *admin;
3120cfd9e7b7SSteen Hegelund
3121cfd9e7b7SSteen Hegelund if (src_cid >= dst_cid)
3122cfd9e7b7SSteen Hegelund return -EFAULT;
3123cfd9e7b7SSteen Hegelund
3124cfd9e7b7SSteen Hegelund admin = vcap_find_admin(vctrl, dst_cid);
3125cfd9e7b7SSteen Hegelund if (!admin)
3126cfd9e7b7SSteen Hegelund return -ENOENT;
312767456717SSteen Hegelund
312867456717SSteen Hegelund eport = kzalloc(sizeof(*eport), GFP_KERNEL);
312967456717SSteen Hegelund if (!eport)
313067456717SSteen Hegelund return -ENOMEM;
313167456717SSteen Hegelund
313267456717SSteen Hegelund eport->ndev = ndev;
313367456717SSteen Hegelund eport->cookie = cookie;
3134cfd9e7b7SSteen Hegelund eport->src_cid = src_cid;
3135cfd9e7b7SSteen Hegelund eport->dst_cid = dst_cid;
3136cfd9e7b7SSteen Hegelund mutex_lock(&admin->lock);
313767456717SSteen Hegelund list_add_tail(&eport->list, &admin->enabled);
3138cfd9e7b7SSteen Hegelund mutex_unlock(&admin->lock);
313967456717SSteen Hegelund
314018a15c76SSteen Hegelund if (vcap_path_exist(vctrl, ndev, src_cid)) {
314118a15c76SSteen Hegelund /* Enable chained lookups */
314218a15c76SSteen Hegelund while (dst_cid) {
314318a15c76SSteen Hegelund admin = vcap_find_admin(vctrl, dst_cid);
314418a15c76SSteen Hegelund if (!admin)
314518a15c76SSteen Hegelund return -ENOENT;
314618a15c76SSteen Hegelund
314718a15c76SSteen Hegelund vcap_enable_rules(vctrl, ndev, dst_cid);
314818a15c76SSteen Hegelund dst_cid = vcap_get_next_chain(vctrl, ndev, dst_cid);
314918a15c76SSteen Hegelund }
315018a15c76SSteen Hegelund }
315167456717SSteen Hegelund return 0;
315267456717SSteen Hegelund }
315367456717SSteen Hegelund
3154cfd9e7b7SSteen Hegelund /* Disable this port and chain id for a VCAP instance */
vcap_disable(struct vcap_control * vctrl,struct net_device * ndev,unsigned long cookie)3155cfd9e7b7SSteen Hegelund static int vcap_disable(struct vcap_control *vctrl, struct net_device *ndev,
315667456717SSteen Hegelund unsigned long cookie)
315767456717SSteen Hegelund {
3158cfd9e7b7SSteen Hegelund struct vcap_enabled_port *elem, *eport = NULL;
3159cfd9e7b7SSteen Hegelund struct vcap_admin *found = NULL, *admin;
316018a15c76SSteen Hegelund int dst_cid;
316167456717SSteen Hegelund
3162cfd9e7b7SSteen Hegelund list_for_each_entry(admin, &vctrl->list, list) {
3163cfd9e7b7SSteen Hegelund list_for_each_entry(elem, &admin->enabled, list) {
3164cfd9e7b7SSteen Hegelund if (elem->cookie == cookie && elem->ndev == ndev) {
3165cfd9e7b7SSteen Hegelund eport = elem;
3166cfd9e7b7SSteen Hegelund found = admin;
3167cfd9e7b7SSteen Hegelund break;
3168cfd9e7b7SSteen Hegelund }
3169cfd9e7b7SSteen Hegelund }
3170cfd9e7b7SSteen Hegelund if (eport)
3171cfd9e7b7SSteen Hegelund break;
3172cfd9e7b7SSteen Hegelund }
3173cfd9e7b7SSteen Hegelund
3174cfd9e7b7SSteen Hegelund if (!eport)
3175cfd9e7b7SSteen Hegelund return -ENOENT;
3176cfd9e7b7SSteen Hegelund
317718a15c76SSteen Hegelund /* Disable chained lookups */
317818a15c76SSteen Hegelund dst_cid = eport->dst_cid;
317918a15c76SSteen Hegelund while (dst_cid) {
318018a15c76SSteen Hegelund admin = vcap_find_admin(vctrl, dst_cid);
318118a15c76SSteen Hegelund if (!admin)
318218a15c76SSteen Hegelund return -ENOENT;
318318a15c76SSteen Hegelund
318418a15c76SSteen Hegelund vcap_disable_rules(vctrl, ndev, dst_cid);
318518a15c76SSteen Hegelund dst_cid = vcap_get_next_chain(vctrl, ndev, dst_cid);
318618a15c76SSteen Hegelund }
318718a15c76SSteen Hegelund
3188cfd9e7b7SSteen Hegelund mutex_lock(&found->lock);
318967456717SSteen Hegelund list_del(&eport->list);
3190cfd9e7b7SSteen Hegelund mutex_unlock(&found->lock);
319167456717SSteen Hegelund kfree(eport);
319267456717SSteen Hegelund return 0;
319367456717SSteen Hegelund }
319467456717SSteen Hegelund
3195cfd9e7b7SSteen Hegelund /* Enable/Disable the VCAP instance lookups */
vcap_enable_lookups(struct vcap_control * vctrl,struct net_device * ndev,int src_cid,int dst_cid,unsigned long cookie,bool enable)319667456717SSteen Hegelund int vcap_enable_lookups(struct vcap_control *vctrl, struct net_device *ndev,
3197cfd9e7b7SSteen Hegelund int src_cid, int dst_cid, unsigned long cookie,
3198cfd9e7b7SSteen Hegelund bool enable)
319967456717SSteen Hegelund {
320067456717SSteen Hegelund int err;
320167456717SSteen Hegelund
320267456717SSteen Hegelund err = vcap_api_check(vctrl);
320367456717SSteen Hegelund if (err)
320467456717SSteen Hegelund return err;
320567456717SSteen Hegelund
320667456717SSteen Hegelund if (!ndev)
320767456717SSteen Hegelund return -ENODEV;
320867456717SSteen Hegelund
3209cfd9e7b7SSteen Hegelund /* Source and destination must be the first chain in a lookup */
3210cfd9e7b7SSteen Hegelund if (src_cid % VCAP_CID_LOOKUP_SIZE)
3211cfd9e7b7SSteen Hegelund return -EFAULT;
3212cfd9e7b7SSteen Hegelund if (dst_cid % VCAP_CID_LOOKUP_SIZE)
321367456717SSteen Hegelund return -EFAULT;
321467456717SSteen Hegelund
3215cfd9e7b7SSteen Hegelund if (enable) {
3216cfd9e7b7SSteen Hegelund if (vcap_is_enabled(vctrl, ndev, dst_cid))
321767456717SSteen Hegelund return -EADDRINUSE;
3218cfd9e7b7SSteen Hegelund if (vcap_is_chain_used(vctrl, ndev, src_cid))
3219cfd9e7b7SSteen Hegelund return -EADDRNOTAVAIL;
3220cfd9e7b7SSteen Hegelund err = vcap_enable(vctrl, ndev, cookie, src_cid, dst_cid);
322167456717SSteen Hegelund } else {
3222cfd9e7b7SSteen Hegelund err = vcap_disable(vctrl, ndev, cookie);
322367456717SSteen Hegelund }
322467456717SSteen Hegelund
3225cfd9e7b7SSteen Hegelund return err;
322667456717SSteen Hegelund }
322767456717SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_enable_lookups);
322867456717SSteen Hegelund
3229784c3067SSteen Hegelund /* Is this chain id the last lookup of all VCAPs */
vcap_is_last_chain(struct vcap_control * vctrl,int cid,bool ingress)3230e7e3f514SSteen Hegelund bool vcap_is_last_chain(struct vcap_control *vctrl, int cid, bool ingress)
3231784c3067SSteen Hegelund {
3232784c3067SSteen Hegelund struct vcap_admin *admin;
3233784c3067SSteen Hegelund int lookup;
3234784c3067SSteen Hegelund
3235784c3067SSteen Hegelund if (vcap_api_check(vctrl))
3236784c3067SSteen Hegelund return false;
3237784c3067SSteen Hegelund
3238784c3067SSteen Hegelund admin = vcap_find_admin(vctrl, cid);
3239784c3067SSteen Hegelund if (!admin)
3240784c3067SSteen Hegelund return false;
3241784c3067SSteen Hegelund
3242e7e3f514SSteen Hegelund if (!vcap_admin_is_last(vctrl, admin, ingress))
324388bd9ea7SSteen Hegelund return false;
324488bd9ea7SSteen Hegelund
3245784c3067SSteen Hegelund /* This must be the last lookup in this VCAP type */
3246784c3067SSteen Hegelund lookup = vcap_chain_id_to_lookup(admin, cid);
3247784c3067SSteen Hegelund return lookup == admin->lookups - 1;
3248784c3067SSteen Hegelund }
3249784c3067SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_is_last_chain);
3250784c3067SSteen Hegelund
3251f13230a4SSteen Hegelund /* Set a rule counter id (for certain vcaps only) */
vcap_rule_set_counter_id(struct vcap_rule * rule,u32 counter_id)3252f13230a4SSteen Hegelund void vcap_rule_set_counter_id(struct vcap_rule *rule, u32 counter_id)
3253f13230a4SSteen Hegelund {
3254f13230a4SSteen Hegelund struct vcap_rule_internal *ri = to_intrule(rule);
3255f13230a4SSteen Hegelund
3256f13230a4SSteen Hegelund ri->counter_id = counter_id;
3257f13230a4SSteen Hegelund }
3258f13230a4SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_set_counter_id);
3259f13230a4SSteen Hegelund
vcap_rule_set_counter(struct vcap_rule * rule,struct vcap_counter * ctr)3260f13230a4SSteen Hegelund int vcap_rule_set_counter(struct vcap_rule *rule, struct vcap_counter *ctr)
3261f13230a4SSteen Hegelund {
3262f13230a4SSteen Hegelund struct vcap_rule_internal *ri = to_intrule(rule);
3263f13230a4SSteen Hegelund int err;
3264f13230a4SSteen Hegelund
3265f13230a4SSteen Hegelund err = vcap_api_check(ri->vctrl);
3266f13230a4SSteen Hegelund if (err)
3267f13230a4SSteen Hegelund return err;
3268f13230a4SSteen Hegelund if (!ctr) {
3269f13230a4SSteen Hegelund pr_err("%s:%d: counter is missing\n", __func__, __LINE__);
3270f13230a4SSteen Hegelund return -EINVAL;
3271f13230a4SSteen Hegelund }
32721972b6d9SSteen Hegelund
32731972b6d9SSteen Hegelund mutex_lock(&ri->admin->lock);
32741972b6d9SSteen Hegelund err = vcap_write_counter(ri, ctr);
32751972b6d9SSteen Hegelund mutex_unlock(&ri->admin->lock);
32761972b6d9SSteen Hegelund
32771972b6d9SSteen Hegelund return err;
3278f13230a4SSteen Hegelund }
3279f13230a4SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_set_counter);
3280f13230a4SSteen Hegelund
vcap_rule_get_counter(struct vcap_rule * rule,struct vcap_counter * ctr)3281f13230a4SSteen Hegelund int vcap_rule_get_counter(struct vcap_rule *rule, struct vcap_counter *ctr)
3282f13230a4SSteen Hegelund {
3283f13230a4SSteen Hegelund struct vcap_rule_internal *ri = to_intrule(rule);
3284f13230a4SSteen Hegelund int err;
3285f13230a4SSteen Hegelund
3286f13230a4SSteen Hegelund err = vcap_api_check(ri->vctrl);
3287f13230a4SSteen Hegelund if (err)
3288f13230a4SSteen Hegelund return err;
3289f13230a4SSteen Hegelund if (!ctr) {
3290f13230a4SSteen Hegelund pr_err("%s:%d: counter is missing\n", __func__, __LINE__);
3291f13230a4SSteen Hegelund return -EINVAL;
3292f13230a4SSteen Hegelund }
32931972b6d9SSteen Hegelund
32941972b6d9SSteen Hegelund mutex_lock(&ri->admin->lock);
32951972b6d9SSteen Hegelund err = vcap_read_counter(ri, ctr);
32961972b6d9SSteen Hegelund mutex_unlock(&ri->admin->lock);
32971972b6d9SSteen Hegelund
32981972b6d9SSteen Hegelund return err;
3299f13230a4SSteen Hegelund }
3300f13230a4SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_get_counter);
3301f13230a4SSteen Hegelund
330218a15c76SSteen Hegelund /* Get a copy of a client key field */
vcap_rule_get_key(struct vcap_rule * rule,enum vcap_key_field key,struct vcap_client_keyfield * ckf)330318a15c76SSteen Hegelund static int vcap_rule_get_key(struct vcap_rule *rule,
330418a15c76SSteen Hegelund enum vcap_key_field key,
330518a15c76SSteen Hegelund struct vcap_client_keyfield *ckf)
330618a15c76SSteen Hegelund {
330718a15c76SSteen Hegelund struct vcap_client_keyfield *field;
330818a15c76SSteen Hegelund
330918a15c76SSteen Hegelund field = vcap_find_keyfield(rule, key);
331018a15c76SSteen Hegelund if (!field)
331118a15c76SSteen Hegelund return -EINVAL;
331218a15c76SSteen Hegelund memcpy(ckf, field, sizeof(*ckf));
331318a15c76SSteen Hegelund INIT_LIST_HEAD(&ckf->ctrl.list);
331418a15c76SSteen Hegelund return 0;
331518a15c76SSteen Hegelund }
331618a15c76SSteen Hegelund
3317c02b19edSSteen Hegelund /* Find a keyset having the same size as the provided rule, where the keyset
3318c02b19edSSteen Hegelund * does not have a type id.
3319c02b19edSSteen Hegelund */
vcap_rule_get_untyped_keyset(struct vcap_rule_internal * ri,struct vcap_keyset_list * matches)3320c02b19edSSteen Hegelund static int vcap_rule_get_untyped_keyset(struct vcap_rule_internal *ri,
3321c02b19edSSteen Hegelund struct vcap_keyset_list *matches)
3322c02b19edSSteen Hegelund {
3323c02b19edSSteen Hegelund struct vcap_control *vctrl = ri->vctrl;
3324c02b19edSSteen Hegelund enum vcap_type vt = ri->admin->vtype;
3325c02b19edSSteen Hegelund const struct vcap_set *keyfield_set;
3326c02b19edSSteen Hegelund int idx;
3327c02b19edSSteen Hegelund
3328c02b19edSSteen Hegelund keyfield_set = vctrl->vcaps[vt].keyfield_set;
3329c02b19edSSteen Hegelund for (idx = 0; idx < vctrl->vcaps[vt].keyfield_set_size; ++idx) {
3330c02b19edSSteen Hegelund if (keyfield_set[idx].sw_per_item == ri->keyset_sw &&
3331c02b19edSSteen Hegelund keyfield_set[idx].type_id == (u8)-1) {
3332c02b19edSSteen Hegelund vcap_keyset_list_add(matches, idx);
3333c02b19edSSteen Hegelund return 0;
3334c02b19edSSteen Hegelund }
3335c02b19edSSteen Hegelund }
3336c02b19edSSteen Hegelund return -EINVAL;
3337c02b19edSSteen Hegelund }
3338c02b19edSSteen Hegelund
333918a15c76SSteen Hegelund /* Get the keysets that matches the rule key type/mask */
vcap_rule_get_keysets(struct vcap_rule_internal * ri,struct vcap_keyset_list * matches)334018a15c76SSteen Hegelund int vcap_rule_get_keysets(struct vcap_rule_internal *ri,
334118a15c76SSteen Hegelund struct vcap_keyset_list *matches)
334218a15c76SSteen Hegelund {
334318a15c76SSteen Hegelund struct vcap_control *vctrl = ri->vctrl;
334418a15c76SSteen Hegelund enum vcap_type vt = ri->admin->vtype;
334518a15c76SSteen Hegelund const struct vcap_set *keyfield_set;
334618a15c76SSteen Hegelund struct vcap_client_keyfield kf = {};
334718a15c76SSteen Hegelund u32 value, mask;
334818a15c76SSteen Hegelund int err, idx;
334918a15c76SSteen Hegelund
335018a15c76SSteen Hegelund err = vcap_rule_get_key(&ri->data, VCAP_KF_TYPE, &kf);
335118a15c76SSteen Hegelund if (err)
3352c02b19edSSteen Hegelund return vcap_rule_get_untyped_keyset(ri, matches);
335318a15c76SSteen Hegelund
335418a15c76SSteen Hegelund if (kf.ctrl.type == VCAP_FIELD_BIT) {
335518a15c76SSteen Hegelund value = kf.data.u1.value;
335618a15c76SSteen Hegelund mask = kf.data.u1.mask;
335718a15c76SSteen Hegelund } else if (kf.ctrl.type == VCAP_FIELD_U32) {
335818a15c76SSteen Hegelund value = kf.data.u32.value;
335918a15c76SSteen Hegelund mask = kf.data.u32.mask;
336018a15c76SSteen Hegelund } else {
336118a15c76SSteen Hegelund return -EINVAL;
336218a15c76SSteen Hegelund }
336318a15c76SSteen Hegelund
336418a15c76SSteen Hegelund keyfield_set = vctrl->vcaps[vt].keyfield_set;
336518a15c76SSteen Hegelund for (idx = 0; idx < vctrl->vcaps[vt].keyfield_set_size; ++idx) {
336618a15c76SSteen Hegelund if (keyfield_set[idx].sw_per_item != ri->keyset_sw)
336718a15c76SSteen Hegelund continue;
336818a15c76SSteen Hegelund
336918a15c76SSteen Hegelund if (keyfield_set[idx].type_id == (u8)-1) {
337018a15c76SSteen Hegelund vcap_keyset_list_add(matches, idx);
337118a15c76SSteen Hegelund continue;
337218a15c76SSteen Hegelund }
337318a15c76SSteen Hegelund
337418a15c76SSteen Hegelund if ((keyfield_set[idx].type_id & mask) == value)
337518a15c76SSteen Hegelund vcap_keyset_list_add(matches, idx);
337618a15c76SSteen Hegelund }
337718a15c76SSteen Hegelund if (matches->cnt > 0)
337818a15c76SSteen Hegelund return 0;
337918a15c76SSteen Hegelund
338018a15c76SSteen Hegelund return -EINVAL;
338118a15c76SSteen Hegelund }
338218a15c76SSteen Hegelund
338327d293ccSSteen Hegelund /* Collect packet counts from all rules with the same cookie */
vcap_get_rule_count_by_cookie(struct vcap_control * vctrl,struct vcap_counter * ctr,u64 cookie)338427d293ccSSteen Hegelund int vcap_get_rule_count_by_cookie(struct vcap_control *vctrl,
338527d293ccSSteen Hegelund struct vcap_counter *ctr, u64 cookie)
338627d293ccSSteen Hegelund {
338727d293ccSSteen Hegelund struct vcap_rule_internal *ri;
338827d293ccSSteen Hegelund struct vcap_counter temp = {};
338927d293ccSSteen Hegelund struct vcap_admin *admin;
339027d293ccSSteen Hegelund int err;
339127d293ccSSteen Hegelund
339227d293ccSSteen Hegelund err = vcap_api_check(vctrl);
339327d293ccSSteen Hegelund if (err)
339427d293ccSSteen Hegelund return err;
339527d293ccSSteen Hegelund
339627d293ccSSteen Hegelund /* Iterate all rules in each VCAP instance */
339727d293ccSSteen Hegelund list_for_each_entry(admin, &vctrl->list, list) {
339827d293ccSSteen Hegelund mutex_lock(&admin->lock);
339927d293ccSSteen Hegelund list_for_each_entry(ri, &admin->rules, list) {
340027d293ccSSteen Hegelund if (ri->data.cookie != cookie)
340127d293ccSSteen Hegelund continue;
340227d293ccSSteen Hegelund
340327d293ccSSteen Hegelund err = vcap_read_counter(ri, &temp);
340427d293ccSSteen Hegelund if (err)
340527d293ccSSteen Hegelund goto unlock;
340627d293ccSSteen Hegelund ctr->value += temp.value;
340727d293ccSSteen Hegelund
340827d293ccSSteen Hegelund /* Reset the rule counter */
340927d293ccSSteen Hegelund temp.value = 0;
341027d293ccSSteen Hegelund temp.sticky = 0;
341127d293ccSSteen Hegelund err = vcap_write_counter(ri, &temp);
341227d293ccSSteen Hegelund if (err)
341327d293ccSSteen Hegelund goto unlock;
341427d293ccSSteen Hegelund }
341527d293ccSSteen Hegelund mutex_unlock(&admin->lock);
341627d293ccSSteen Hegelund }
341727d293ccSSteen Hegelund return err;
341827d293ccSSteen Hegelund
341927d293ccSSteen Hegelund unlock:
342027d293ccSSteen Hegelund mutex_unlock(&admin->lock);
342127d293ccSSteen Hegelund return err;
342227d293ccSSteen Hegelund }
342327d293ccSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_get_rule_count_by_cookie);
342427d293ccSSteen Hegelund
vcap_rule_mod_key(struct vcap_rule * rule,enum vcap_key_field key,enum vcap_field_type ftype,struct vcap_client_keyfield_data * data)3425465a38a2SSteen Hegelund static int vcap_rule_mod_key(struct vcap_rule *rule,
3426465a38a2SSteen Hegelund enum vcap_key_field key,
3427465a38a2SSteen Hegelund enum vcap_field_type ftype,
3428465a38a2SSteen Hegelund struct vcap_client_keyfield_data *data)
3429465a38a2SSteen Hegelund {
3430465a38a2SSteen Hegelund struct vcap_client_keyfield *field;
3431465a38a2SSteen Hegelund
3432465a38a2SSteen Hegelund field = vcap_find_keyfield(rule, key);
3433465a38a2SSteen Hegelund if (!field)
3434465a38a2SSteen Hegelund return vcap_rule_add_key(rule, key, ftype, data);
343533e3a273SSteen Hegelund memcpy(&field->data, data, sizeof(field->data));
3436465a38a2SSteen Hegelund return 0;
3437465a38a2SSteen Hegelund }
3438465a38a2SSteen Hegelund
3439465a38a2SSteen Hegelund /* Modify a 32 bit key field with value and mask in the rule */
vcap_rule_mod_key_u32(struct vcap_rule * rule,enum vcap_key_field key,u32 value,u32 mask)3440465a38a2SSteen Hegelund int vcap_rule_mod_key_u32(struct vcap_rule *rule, enum vcap_key_field key,
3441465a38a2SSteen Hegelund u32 value, u32 mask)
3442465a38a2SSteen Hegelund {
3443465a38a2SSteen Hegelund struct vcap_client_keyfield_data data;
3444465a38a2SSteen Hegelund
3445465a38a2SSteen Hegelund data.u32.value = value;
3446465a38a2SSteen Hegelund data.u32.mask = mask;
3447465a38a2SSteen Hegelund return vcap_rule_mod_key(rule, key, VCAP_FIELD_U32, &data);
3448465a38a2SSteen Hegelund }
3449465a38a2SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_mod_key_u32);
3450465a38a2SSteen Hegelund
3451bfcb94aaSSteen Hegelund /* Remove a key field with value and mask in the rule */
vcap_rule_rem_key(struct vcap_rule * rule,enum vcap_key_field key)3452bfcb94aaSSteen Hegelund int vcap_rule_rem_key(struct vcap_rule *rule, enum vcap_key_field key)
3453bfcb94aaSSteen Hegelund {
3454bfcb94aaSSteen Hegelund struct vcap_rule_internal *ri = to_intrule(rule);
3455bfcb94aaSSteen Hegelund struct vcap_client_keyfield *field;
3456bfcb94aaSSteen Hegelund
3457bfcb94aaSSteen Hegelund field = vcap_find_keyfield(rule, key);
3458bfcb94aaSSteen Hegelund if (!field) {
3459bfcb94aaSSteen Hegelund pr_err("%s:%d: key %s is not in the rule\n",
3460bfcb94aaSSteen Hegelund __func__, __LINE__, vcap_keyfield_name(ri->vctrl, key));
3461bfcb94aaSSteen Hegelund return -EINVAL;
3462bfcb94aaSSteen Hegelund }
3463bfcb94aaSSteen Hegelund /* Deallocate the key field */
3464bfcb94aaSSteen Hegelund list_del(&field->ctrl.list);
3465bfcb94aaSSteen Hegelund kfree(field);
3466bfcb94aaSSteen Hegelund return 0;
3467bfcb94aaSSteen Hegelund }
3468bfcb94aaSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_rem_key);
3469bfcb94aaSSteen Hegelund
vcap_rule_mod_action(struct vcap_rule * rule,enum vcap_action_field action,enum vcap_field_type ftype,struct vcap_client_actionfield_data * data)3470465a38a2SSteen Hegelund static int vcap_rule_mod_action(struct vcap_rule *rule,
3471465a38a2SSteen Hegelund enum vcap_action_field action,
3472465a38a2SSteen Hegelund enum vcap_field_type ftype,
3473465a38a2SSteen Hegelund struct vcap_client_actionfield_data *data)
3474465a38a2SSteen Hegelund {
3475465a38a2SSteen Hegelund struct vcap_client_actionfield *field;
3476465a38a2SSteen Hegelund
3477465a38a2SSteen Hegelund field = vcap_find_actionfield(rule, action);
3478465a38a2SSteen Hegelund if (!field)
3479465a38a2SSteen Hegelund return vcap_rule_add_action(rule, action, ftype, data);
348033e3a273SSteen Hegelund memcpy(&field->data, data, sizeof(field->data));
3481465a38a2SSteen Hegelund return 0;
3482465a38a2SSteen Hegelund }
3483465a38a2SSteen Hegelund
3484465a38a2SSteen Hegelund /* Modify a 32 bit action field with value in the rule */
vcap_rule_mod_action_u32(struct vcap_rule * rule,enum vcap_action_field action,u32 value)3485465a38a2SSteen Hegelund int vcap_rule_mod_action_u32(struct vcap_rule *rule,
3486465a38a2SSteen Hegelund enum vcap_action_field action,
3487465a38a2SSteen Hegelund u32 value)
3488465a38a2SSteen Hegelund {
3489465a38a2SSteen Hegelund struct vcap_client_actionfield_data data;
3490465a38a2SSteen Hegelund
3491465a38a2SSteen Hegelund data.u32.value = value;
3492465a38a2SSteen Hegelund return vcap_rule_mod_action(rule, action, VCAP_FIELD_U32, &data);
3493465a38a2SSteen Hegelund }
3494465a38a2SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_mod_action_u32);
3495465a38a2SSteen Hegelund
3496465a38a2SSteen Hegelund /* Drop keys in a keylist and any keys that are not supported by the keyset */
vcap_filter_rule_keys(struct vcap_rule * rule,enum vcap_key_field keylist[],int length,bool drop_unsupported)3497465a38a2SSteen Hegelund int vcap_filter_rule_keys(struct vcap_rule *rule,
3498465a38a2SSteen Hegelund enum vcap_key_field keylist[], int length,
3499465a38a2SSteen Hegelund bool drop_unsupported)
3500465a38a2SSteen Hegelund {
3501465a38a2SSteen Hegelund struct vcap_rule_internal *ri = to_intrule(rule);
3502465a38a2SSteen Hegelund struct vcap_client_keyfield *ckf, *next_ckf;
3503465a38a2SSteen Hegelund const struct vcap_field *fields;
3504465a38a2SSteen Hegelund enum vcap_key_field key;
3505465a38a2SSteen Hegelund int err = 0;
3506465a38a2SSteen Hegelund int idx;
3507465a38a2SSteen Hegelund
3508465a38a2SSteen Hegelund if (length > 0) {
3509465a38a2SSteen Hegelund err = -EEXIST;
3510465a38a2SSteen Hegelund list_for_each_entry_safe(ckf, next_ckf,
3511465a38a2SSteen Hegelund &ri->data.keyfields, ctrl.list) {
3512465a38a2SSteen Hegelund key = ckf->ctrl.key;
3513465a38a2SSteen Hegelund for (idx = 0; idx < length; ++idx)
3514465a38a2SSteen Hegelund if (key == keylist[idx]) {
3515465a38a2SSteen Hegelund list_del(&ckf->ctrl.list);
3516465a38a2SSteen Hegelund kfree(ckf);
3517465a38a2SSteen Hegelund idx++;
3518465a38a2SSteen Hegelund err = 0;
3519465a38a2SSteen Hegelund }
3520465a38a2SSteen Hegelund }
3521465a38a2SSteen Hegelund }
3522465a38a2SSteen Hegelund if (drop_unsupported) {
3523465a38a2SSteen Hegelund err = -EEXIST;
3524465a38a2SSteen Hegelund fields = vcap_keyfields(ri->vctrl, ri->admin->vtype,
3525465a38a2SSteen Hegelund rule->keyset);
3526465a38a2SSteen Hegelund if (!fields)
3527465a38a2SSteen Hegelund return err;
3528465a38a2SSteen Hegelund list_for_each_entry_safe(ckf, next_ckf,
3529465a38a2SSteen Hegelund &ri->data.keyfields, ctrl.list) {
3530465a38a2SSteen Hegelund key = ckf->ctrl.key;
3531465a38a2SSteen Hegelund if (fields[key].width == 0) {
3532465a38a2SSteen Hegelund list_del(&ckf->ctrl.list);
3533465a38a2SSteen Hegelund kfree(ckf);
3534465a38a2SSteen Hegelund err = 0;
3535465a38a2SSteen Hegelund }
3536465a38a2SSteen Hegelund }
3537465a38a2SSteen Hegelund }
3538465a38a2SSteen Hegelund return err;
3539465a38a2SSteen Hegelund }
3540465a38a2SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_filter_rule_keys);
3541465a38a2SSteen Hegelund
3542bfcb94aaSSteen Hegelund /* Select the keyset from the list that results in the smallest rule size */
3543bfcb94aaSSteen Hegelund enum vcap_keyfield_set
vcap_select_min_rule_keyset(struct vcap_control * vctrl,enum vcap_type vtype,struct vcap_keyset_list * kslist)3544bfcb94aaSSteen Hegelund vcap_select_min_rule_keyset(struct vcap_control *vctrl,
3545bfcb94aaSSteen Hegelund enum vcap_type vtype,
3546bfcb94aaSSteen Hegelund struct vcap_keyset_list *kslist)
3547bfcb94aaSSteen Hegelund {
3548bfcb94aaSSteen Hegelund enum vcap_keyfield_set ret = VCAP_KFS_NO_VALUE;
3549bfcb94aaSSteen Hegelund const struct vcap_set *kset;
3550bfcb94aaSSteen Hegelund int max = 100, idx;
3551bfcb94aaSSteen Hegelund
3552bfcb94aaSSteen Hegelund for (idx = 0; idx < kslist->cnt; ++idx) {
3553bfcb94aaSSteen Hegelund kset = vcap_keyfieldset(vctrl, vtype, kslist->keysets[idx]);
3554bfcb94aaSSteen Hegelund if (!kset)
3555bfcb94aaSSteen Hegelund continue;
3556bfcb94aaSSteen Hegelund if (kset->sw_per_item >= max)
3557bfcb94aaSSteen Hegelund continue;
3558bfcb94aaSSteen Hegelund max = kset->sw_per_item;
3559bfcb94aaSSteen Hegelund ret = kslist->keysets[idx];
3560bfcb94aaSSteen Hegelund }
3561bfcb94aaSSteen Hegelund return ret;
3562bfcb94aaSSteen Hegelund }
3563bfcb94aaSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_select_min_rule_keyset);
3564bfcb94aaSSteen Hegelund
3565465a38a2SSteen Hegelund /* Make a full copy of an existing rule with a new rule id */
vcap_copy_rule(struct vcap_rule * erule)3566465a38a2SSteen Hegelund struct vcap_rule *vcap_copy_rule(struct vcap_rule *erule)
3567465a38a2SSteen Hegelund {
3568465a38a2SSteen Hegelund struct vcap_rule_internal *ri = to_intrule(erule);
3569465a38a2SSteen Hegelund struct vcap_client_actionfield *caf;
3570465a38a2SSteen Hegelund struct vcap_client_keyfield *ckf;
3571465a38a2SSteen Hegelund struct vcap_rule *rule;
3572465a38a2SSteen Hegelund int err;
3573465a38a2SSteen Hegelund
3574465a38a2SSteen Hegelund err = vcap_api_check(ri->vctrl);
3575465a38a2SSteen Hegelund if (err)
3576465a38a2SSteen Hegelund return ERR_PTR(err);
3577465a38a2SSteen Hegelund
3578465a38a2SSteen Hegelund rule = vcap_alloc_rule(ri->vctrl, ri->ndev, ri->data.vcap_chain_id,
3579465a38a2SSteen Hegelund ri->data.user, ri->data.priority, 0);
3580465a38a2SSteen Hegelund if (IS_ERR(rule))
3581465a38a2SSteen Hegelund return rule;
3582465a38a2SSteen Hegelund
3583465a38a2SSteen Hegelund list_for_each_entry(ckf, &ri->data.keyfields, ctrl.list) {
3584465a38a2SSteen Hegelund /* Add a key duplicate in the new rule */
3585465a38a2SSteen Hegelund err = vcap_rule_add_key(rule,
3586465a38a2SSteen Hegelund ckf->ctrl.key,
3587465a38a2SSteen Hegelund ckf->ctrl.type,
3588465a38a2SSteen Hegelund &ckf->data);
3589465a38a2SSteen Hegelund if (err)
3590465a38a2SSteen Hegelund goto err;
3591465a38a2SSteen Hegelund }
3592465a38a2SSteen Hegelund
3593465a38a2SSteen Hegelund list_for_each_entry(caf, &ri->data.actionfields, ctrl.list) {
3594465a38a2SSteen Hegelund /* Add a action duplicate in the new rule */
3595465a38a2SSteen Hegelund err = vcap_rule_add_action(rule,
3596465a38a2SSteen Hegelund caf->ctrl.action,
3597465a38a2SSteen Hegelund caf->ctrl.type,
3598465a38a2SSteen Hegelund &caf->data);
3599465a38a2SSteen Hegelund if (err)
3600465a38a2SSteen Hegelund goto err;
3601465a38a2SSteen Hegelund }
3602465a38a2SSteen Hegelund return rule;
3603465a38a2SSteen Hegelund err:
3604465a38a2SSteen Hegelund vcap_free_rule(rule);
3605465a38a2SSteen Hegelund return ERR_PTR(err);
3606465a38a2SSteen Hegelund }
3607465a38a2SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_copy_rule);
3608465a38a2SSteen Hegelund
360967d63751SSteen Hegelund #ifdef CONFIG_VCAP_KUNIT_TEST
361067d63751SSteen Hegelund #include "vcap_api_kunit.c"
361167d63751SSteen Hegelund #endif
3612