Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : *
3 : : * Copyright(c) 2019-2021 Xilinx, Inc.
4 : : * Copyright(c) 2017-2019 Solarflare Communications Inc.
5 : : *
6 : : * This software was jointly developed between OKTET Labs (under contract
7 : : * for Solarflare) and Solarflare Communications, Inc.
8 : : */
9 : :
10 : : #include <stdbool.h>
11 : :
12 : : #include <rte_byteorder.h>
13 : : #include <rte_tailq.h>
14 : : #include <rte_common.h>
15 : : #include <ethdev_driver.h>
16 : : #include <rte_ether.h>
17 : : #include <rte_flow.h>
18 : : #include <rte_flow_driver.h>
19 : :
20 : : #include "efx.h"
21 : :
22 : : #include "sfc.h"
23 : : #include "sfc_debug.h"
24 : : #include "sfc_rx.h"
25 : : #include "sfc_filter.h"
26 : : #include "sfc_flow.h"
27 : : #include "sfc_flow_rss.h"
28 : : #include "sfc_flow_tunnel.h"
29 : : #include "sfc_log.h"
30 : : #include "sfc_dp_rx.h"
31 : : #include "sfc_mae_counter.h"
32 : : #include "sfc_switch.h"
33 : :
34 : : struct sfc_flow_ops_by_spec {
35 : : sfc_flow_parse_cb_t *parse;
36 : : sfc_flow_verify_cb_t *verify;
37 : : sfc_flow_cleanup_cb_t *cleanup;
38 : : sfc_flow_insert_cb_t *insert;
39 : : sfc_flow_remove_cb_t *remove;
40 : : sfc_flow_query_cb_t *query;
41 : : };
42 : :
43 : : static sfc_flow_parse_cb_t sfc_flow_parse_rte_to_filter;
44 : : static sfc_flow_parse_cb_t sfc_flow_parse_rte_to_mae;
45 : : static sfc_flow_insert_cb_t sfc_flow_filter_insert;
46 : : static sfc_flow_remove_cb_t sfc_flow_filter_remove;
47 : : static sfc_flow_cleanup_cb_t sfc_flow_cleanup;
48 : :
49 : : static const struct sfc_flow_ops_by_spec sfc_flow_ops_filter = {
50 : : .parse = sfc_flow_parse_rte_to_filter,
51 : : .verify = NULL,
52 : : .cleanup = sfc_flow_cleanup,
53 : : .insert = sfc_flow_filter_insert,
54 : : .remove = sfc_flow_filter_remove,
55 : : .query = NULL,
56 : : };
57 : :
58 : : static const struct sfc_flow_ops_by_spec sfc_flow_ops_mae = {
59 : : .parse = sfc_flow_parse_rte_to_mae,
60 : : .verify = sfc_mae_flow_verify,
61 : : .cleanup = sfc_mae_flow_cleanup,
62 : : .insert = sfc_mae_flow_insert,
63 : : .remove = sfc_mae_flow_remove,
64 : : .query = sfc_mae_flow_query,
65 : : };
66 : :
67 : : static const struct sfc_flow_ops_by_spec *
68 : : sfc_flow_get_ops_by_spec(struct rte_flow *flow)
69 : : {
70 : : struct sfc_flow_spec *spec = &flow->spec;
71 : : const struct sfc_flow_ops_by_spec *ops = NULL;
72 : :
73 [ # # # # : 0 : switch (spec->type) {
# # ]
74 : : case SFC_FLOW_SPEC_FILTER:
75 : : ops = &sfc_flow_ops_filter;
76 : : break;
77 : 0 : case SFC_FLOW_SPEC_MAE:
78 : : ops = &sfc_flow_ops_mae;
79 : 0 : break;
80 : : default:
81 : : SFC_ASSERT(false);
82 : : break;
83 : : }
84 : :
85 : : return ops;
86 : : }
87 : :
88 : : /*
89 : : * Currently, filter-based (VNIC) flow API is implemented in such a manner
90 : : * that each flow rule is converted to one or more hardware filters.
91 : : * All elements of flow rule (attributes, pattern items, actions)
92 : : * correspond to one or more fields in the efx_filter_spec_s structure
93 : : * that is responsible for the hardware filter.
94 : : * If some required field is unset in the flow rule, then a handful
95 : : * of filter copies will be created to cover all possible values
96 : : * of such a field.
97 : : */
98 : :
99 : : static sfc_flow_item_parse sfc_flow_parse_void;
100 : : static sfc_flow_item_parse sfc_flow_parse_eth;
101 : : static sfc_flow_item_parse sfc_flow_parse_vlan;
102 : : static sfc_flow_item_parse sfc_flow_parse_ipv4;
103 : : static sfc_flow_item_parse sfc_flow_parse_ipv6;
104 : : static sfc_flow_item_parse sfc_flow_parse_tcp;
105 : : static sfc_flow_item_parse sfc_flow_parse_udp;
106 : : static sfc_flow_item_parse sfc_flow_parse_vxlan;
107 : : static sfc_flow_item_parse sfc_flow_parse_geneve;
108 : : static sfc_flow_item_parse sfc_flow_parse_nvgre;
109 : : static sfc_flow_item_parse sfc_flow_parse_pppoex;
110 : :
111 : : typedef int (sfc_flow_spec_set_vals)(struct sfc_flow_spec *spec,
112 : : unsigned int filters_count_for_one_val,
113 : : struct rte_flow_error *error);
114 : :
115 : : typedef boolean_t (sfc_flow_spec_check)(efx_filter_match_flags_t match,
116 : : efx_filter_spec_t *spec,
117 : : struct sfc_filter *filter);
118 : :
119 : : struct sfc_flow_copy_flag {
120 : : /* EFX filter specification match flag */
121 : : efx_filter_match_flags_t flag;
122 : : /* Number of values of corresponding field */
123 : : unsigned int vals_count;
124 : : /* Function to set values in specifications */
125 : : sfc_flow_spec_set_vals *set_vals;
126 : : /*
127 : : * Function to check that the specification is suitable
128 : : * for adding this match flag
129 : : */
130 : : sfc_flow_spec_check *spec_check;
131 : : };
132 : :
133 : : static sfc_flow_spec_set_vals sfc_flow_set_unknown_dst_flags;
134 : : static sfc_flow_spec_check sfc_flow_check_unknown_dst_flags;
135 : : static sfc_flow_spec_set_vals sfc_flow_set_ethertypes;
136 : : static sfc_flow_spec_set_vals sfc_flow_set_ifrm_unknown_dst_flags;
137 : : static sfc_flow_spec_check sfc_flow_check_ifrm_unknown_dst_flags;
138 : : static sfc_flow_spec_set_vals sfc_flow_set_outer_vid_flag;
139 : : static sfc_flow_spec_check sfc_flow_check_outer_vid_flag;
140 : :
141 : : static boolean_t
142 : : sfc_flow_is_zero(const uint8_t *buf, unsigned int size)
143 : : {
144 : : uint8_t sum = 0;
145 : : unsigned int i;
146 : :
147 [ # # # # : 0 : for (i = 0; i < size; i++)
# # # # ]
148 : 0 : sum |= buf[i];
149 : :
150 : : return (sum == 0) ? B_TRUE : B_FALSE;
151 : : }
152 : :
153 : : /*
154 : : * Validate item and prepare structures spec and mask for parsing
155 : : */
156 : : int
157 : 0 : sfc_flow_parse_init(const struct rte_flow_item *item,
158 : : const void **spec_ptr,
159 : : const void **mask_ptr,
160 : : const void *supp_mask,
161 : : const void *def_mask,
162 : : unsigned int size,
163 : : struct rte_flow_error *error)
164 : : {
165 : : const uint8_t *spec;
166 : : const uint8_t *mask;
167 : : const uint8_t *last;
168 : : uint8_t supp;
169 : : unsigned int i;
170 : :
171 [ # # ]: 0 : if (item == NULL) {
172 : 0 : rte_flow_error_set(error, EINVAL,
173 : : RTE_FLOW_ERROR_TYPE_ITEM, NULL,
174 : : "NULL item");
175 : 0 : return -rte_errno;
176 : : }
177 : :
178 [ # # # # : 0 : if ((item->last != NULL || item->mask != NULL) && item->spec == NULL) {
# # ]
179 : 0 : rte_flow_error_set(error, EINVAL,
180 : : RTE_FLOW_ERROR_TYPE_ITEM, item,
181 : : "Mask or last is set without spec");
182 : 0 : return -rte_errno;
183 : : }
184 : :
185 : : /*
186 : : * If "mask" is not set, default mask is used,
187 : : * but if default mask is NULL, "mask" should be set
188 : : */
189 [ # # ]: 0 : if (item->mask == NULL) {
190 [ # # ]: 0 : if (def_mask == NULL) {
191 : 0 : rte_flow_error_set(error, EINVAL,
192 : : RTE_FLOW_ERROR_TYPE_ITEM, NULL,
193 : : "Mask should be specified");
194 : 0 : return -rte_errno;
195 : : }
196 : :
197 : : mask = def_mask;
198 : : } else {
199 : : mask = item->mask;
200 : : }
201 : :
202 : 0 : spec = item->spec;
203 : : last = item->last;
204 : :
205 [ # # ]: 0 : if (spec == NULL)
206 : 0 : goto exit;
207 : :
208 : : /*
209 : : * If field values in "last" are either 0 or equal to the corresponding
210 : : * values in "spec" then they are ignored
211 : : */
212 [ # # # # ]: 0 : if (last != NULL &&
213 : 0 : !sfc_flow_is_zero(last, size) &&
214 [ # # ]: 0 : memcmp(last, spec, size) != 0) {
215 : 0 : rte_flow_error_set(error, ENOTSUP,
216 : : RTE_FLOW_ERROR_TYPE_ITEM, item,
217 : : "Ranging is not supported");
218 : 0 : return -rte_errno;
219 : : }
220 : :
221 [ # # ]: 0 : if (supp_mask == NULL) {
222 : 0 : rte_flow_error_set(error, EINVAL,
223 : : RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
224 : : "Supported mask for item should be specified");
225 : 0 : return -rte_errno;
226 : : }
227 : :
228 : : /* Check that mask does not ask for more match than supp_mask */
229 [ # # ]: 0 : for (i = 0; i < size; i++) {
230 : 0 : supp = ((const uint8_t *)supp_mask)[i];
231 : :
232 [ # # ]: 0 : if (~supp & mask[i]) {
233 : 0 : rte_flow_error_set(error, ENOTSUP,
234 : : RTE_FLOW_ERROR_TYPE_ITEM, item,
235 : : "Item's field is not supported");
236 : 0 : return -rte_errno;
237 : : }
238 : : }
239 : :
240 : 0 : exit:
241 : 0 : *spec_ptr = spec;
242 : 0 : *mask_ptr = mask;
243 : 0 : return 0;
244 : : }
245 : :
246 : : /*
247 : : * Protocol parsers.
248 : : * Masking is not supported, so masks in items should be either
249 : : * full or empty (zeroed) and set only for supported fields which
250 : : * are specified in the supp_mask.
251 : : */
252 : :
253 : : static int
254 : 0 : sfc_flow_parse_void(__rte_unused const struct rte_flow_item *item,
255 : : __rte_unused struct sfc_flow_parse_ctx *parse_ctx,
256 : : __rte_unused struct rte_flow_error *error)
257 : : {
258 : 0 : return 0;
259 : : }
260 : :
261 : : /**
262 : : * Convert Ethernet item to EFX filter specification.
263 : : *
264 : : * @param item[in]
265 : : * Item specification. Outer frame specification may only comprise
266 : : * source/destination addresses and Ethertype field.
267 : : * Inner frame specification may contain destination address only.
268 : : * There is support for individual/group mask as well as for empty and full.
269 : : * If the mask is NULL, default mask will be used. Ranging is not supported.
270 : : * @param efx_spec[in, out]
271 : : * EFX filter specification to update.
272 : : * @param[out] error
273 : : * Perform verbose error reporting if not NULL.
274 : : */
275 : : static int
276 : 0 : sfc_flow_parse_eth(const struct rte_flow_item *item,
277 : : struct sfc_flow_parse_ctx *parse_ctx,
278 : : struct rte_flow_error *error)
279 : : {
280 : : int rc;
281 : 0 : efx_filter_spec_t *efx_spec = parse_ctx->filter;
282 : 0 : const struct rte_flow_item_eth *spec = NULL;
283 : 0 : const struct rte_flow_item_eth *mask = NULL;
284 : 0 : const struct rte_flow_item_eth supp_mask = {
285 : : .hdr.dst_addr.addr_bytes = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
286 : : .hdr.src_addr.addr_bytes = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
287 : : .hdr.ether_type = 0xffff,
288 : : };
289 : 0 : const struct rte_flow_item_eth ifrm_supp_mask = {
290 : : .hdr.dst_addr.addr_bytes = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
291 : : };
292 : 0 : const uint8_t ig_mask[EFX_MAC_ADDR_LEN] = {
293 : : 0x01, 0x00, 0x00, 0x00, 0x00, 0x00
294 : : };
295 : : const struct rte_flow_item_eth *supp_mask_p;
296 : : const struct rte_flow_item_eth *def_mask_p;
297 : : uint8_t *loc_mac = NULL;
298 : 0 : boolean_t is_ifrm = (efx_spec->efs_encap_type !=
299 : : EFX_TUNNEL_PROTOCOL_NONE);
300 : :
301 [ # # ]: 0 : if (is_ifrm) {
302 : : supp_mask_p = &ifrm_supp_mask;
303 : : def_mask_p = &ifrm_supp_mask;
304 : 0 : loc_mac = efx_spec->efs_ifrm_loc_mac;
305 : : } else {
306 : : supp_mask_p = &supp_mask;
307 : : def_mask_p = &rte_flow_item_eth_mask;
308 : 0 : loc_mac = efx_spec->efs_loc_mac;
309 : : }
310 : :
311 : 0 : rc = sfc_flow_parse_init(item,
312 : : (const void **)&spec,
313 : : (const void **)&mask,
314 : : supp_mask_p, def_mask_p,
315 : : sizeof(struct rte_flow_item_eth),
316 : : error);
317 [ # # ]: 0 : if (rc != 0)
318 : : return rc;
319 : :
320 : : /* If "spec" is not set, could be any Ethernet */
321 [ # # ]: 0 : if (spec == NULL)
322 : : return 0;
323 : :
324 [ # # ]: 0 : if (rte_is_same_ether_addr(&mask->hdr.dst_addr, &supp_mask.hdr.dst_addr)) {
325 : 0 : efx_spec->efs_match_flags |= is_ifrm ?
326 [ # # ]: 0 : EFX_FILTER_MATCH_IFRM_LOC_MAC :
327 : : EFX_FILTER_MATCH_LOC_MAC;
328 [ # # ]: 0 : rte_memcpy(loc_mac, spec->hdr.dst_addr.addr_bytes,
329 : : EFX_MAC_ADDR_LEN);
330 [ # # ]: 0 : } else if (memcmp(mask->hdr.dst_addr.addr_bytes, ig_mask,
331 : : EFX_MAC_ADDR_LEN) == 0) {
332 [ # # ]: 0 : if (rte_is_unicast_ether_addr(&spec->hdr.dst_addr))
333 : 0 : efx_spec->efs_match_flags |= is_ifrm ?
334 [ # # ]: 0 : EFX_FILTER_MATCH_IFRM_UNKNOWN_UCAST_DST :
335 : : EFX_FILTER_MATCH_UNKNOWN_UCAST_DST;
336 : : else
337 : 0 : efx_spec->efs_match_flags |= is_ifrm ?
338 [ # # ]: 0 : EFX_FILTER_MATCH_IFRM_UNKNOWN_MCAST_DST :
339 : : EFX_FILTER_MATCH_UNKNOWN_MCAST_DST;
340 [ # # ]: 0 : } else if (!rte_is_zero_ether_addr(&mask->hdr.dst_addr)) {
341 : 0 : goto fail_bad_mask;
342 : : }
343 : :
344 : : /*
345 : : * ifrm_supp_mask ensures that the source address and
346 : : * ethertype masks are equal to zero in inner frame,
347 : : * so these fields are filled in only for the outer frame
348 : : */
349 [ # # ]: 0 : if (rte_is_same_ether_addr(&mask->hdr.src_addr, &supp_mask.hdr.src_addr)) {
350 : 0 : efx_spec->efs_match_flags |= EFX_FILTER_MATCH_REM_MAC;
351 [ # # ]: 0 : rte_memcpy(efx_spec->efs_rem_mac, spec->hdr.src_addr.addr_bytes,
352 : : EFX_MAC_ADDR_LEN);
353 [ # # ]: 0 : } else if (!rte_is_zero_ether_addr(&mask->hdr.src_addr)) {
354 : 0 : goto fail_bad_mask;
355 : : }
356 : :
357 : : /*
358 : : * Ether type is in big-endian byte order in item and
359 : : * in little-endian in efx_spec, so byte swap is used
360 : : */
361 [ # # ]: 0 : if (mask->hdr.ether_type == supp_mask.hdr.ether_type) {
362 : 0 : efx_spec->efs_match_flags |= EFX_FILTER_MATCH_ETHER_TYPE;
363 [ # # ]: 0 : efx_spec->efs_ether_type = rte_bswap16(spec->hdr.ether_type);
364 [ # # ]: 0 : } else if (mask->hdr.ether_type != 0) {
365 : 0 : goto fail_bad_mask;
366 : : }
367 : :
368 : : return 0;
369 : :
370 : 0 : fail_bad_mask:
371 : 0 : rte_flow_error_set(error, EINVAL,
372 : : RTE_FLOW_ERROR_TYPE_ITEM, item,
373 : : "Bad mask in the ETH pattern item");
374 : 0 : return -rte_errno;
375 : : }
376 : :
377 : : /**
378 : : * Convert VLAN item to EFX filter specification.
379 : : *
380 : : * @param item[in]
381 : : * Item specification. Only VID field is supported.
382 : : * The mask can not be NULL. Ranging is not supported.
383 : : * @param efx_spec[in, out]
384 : : * EFX filter specification to update.
385 : : * @param[out] error
386 : : * Perform verbose error reporting if not NULL.
387 : : */
388 : : static int
389 : 0 : sfc_flow_parse_vlan(const struct rte_flow_item *item,
390 : : struct sfc_flow_parse_ctx *parse_ctx,
391 : : struct rte_flow_error *error)
392 : : {
393 : : int rc;
394 : : uint16_t vid;
395 : 0 : efx_filter_spec_t *efx_spec = parse_ctx->filter;
396 : 0 : const struct rte_flow_item_vlan *spec = NULL;
397 : 0 : const struct rte_flow_item_vlan *mask = NULL;
398 : 0 : const struct rte_flow_item_vlan supp_mask = {
399 : : .hdr.vlan_tci = rte_cpu_to_be_16(RTE_ETH_VLAN_ID_MAX),
400 : : .hdr.eth_proto = RTE_BE16(0xffff),
401 : : };
402 : :
403 : 0 : rc = sfc_flow_parse_init(item,
404 : : (const void **)&spec,
405 : : (const void **)&mask,
406 : : &supp_mask,
407 : : NULL,
408 : : sizeof(struct rte_flow_item_vlan),
409 : : error);
410 [ # # ]: 0 : if (rc != 0)
411 : : return rc;
412 : :
413 : : /*
414 : : * VID is in big-endian byte order in item and
415 : : * in little-endian in efx_spec, so byte swap is used.
416 : : * If two VLAN items are included, the first matches
417 : : * the outer tag and the next matches the inner tag.
418 : : */
419 [ # # ]: 0 : if (mask->hdr.vlan_tci == supp_mask.hdr.vlan_tci) {
420 : : /* Apply mask to keep VID only */
421 [ # # ]: 0 : vid = rte_bswap16(spec->hdr.vlan_tci & mask->hdr.vlan_tci);
422 : :
423 [ # # ]: 0 : if (!(efx_spec->efs_match_flags &
424 : : EFX_FILTER_MATCH_OUTER_VID)) {
425 : 0 : efx_spec->efs_match_flags |= EFX_FILTER_MATCH_OUTER_VID;
426 : 0 : efx_spec->efs_outer_vid = vid;
427 [ # # ]: 0 : } else if (!(efx_spec->efs_match_flags &
428 : : EFX_FILTER_MATCH_INNER_VID)) {
429 : 0 : efx_spec->efs_match_flags |= EFX_FILTER_MATCH_INNER_VID;
430 : 0 : efx_spec->efs_inner_vid = vid;
431 : : } else {
432 : 0 : rte_flow_error_set(error, EINVAL,
433 : : RTE_FLOW_ERROR_TYPE_ITEM, item,
434 : : "More than two VLAN items");
435 : 0 : return -rte_errno;
436 : : }
437 : : } else {
438 : 0 : rte_flow_error_set(error, EINVAL,
439 : : RTE_FLOW_ERROR_TYPE_ITEM, item,
440 : : "VLAN ID in TCI match is required");
441 : 0 : return -rte_errno;
442 : : }
443 : :
444 [ # # ]: 0 : if (efx_spec->efs_match_flags & EFX_FILTER_MATCH_ETHER_TYPE) {
445 : 0 : rte_flow_error_set(error, EINVAL,
446 : : RTE_FLOW_ERROR_TYPE_ITEM, item,
447 : : "VLAN TPID matching is not supported");
448 : 0 : return -rte_errno;
449 : : }
450 [ # # ]: 0 : if (mask->hdr.eth_proto == supp_mask.hdr.eth_proto) {
451 : 0 : efx_spec->efs_match_flags |= EFX_FILTER_MATCH_ETHER_TYPE;
452 [ # # ]: 0 : efx_spec->efs_ether_type = rte_bswap16(spec->hdr.eth_proto);
453 [ # # ]: 0 : } else if (mask->hdr.eth_proto) {
454 : 0 : rte_flow_error_set(error, EINVAL,
455 : : RTE_FLOW_ERROR_TYPE_ITEM, item,
456 : : "Bad mask for VLAN inner type");
457 : 0 : return -rte_errno;
458 : : }
459 : :
460 : : return 0;
461 : : }
462 : :
463 : : /**
464 : : * Convert IPv4 item to EFX filter specification.
465 : : *
466 : : * @param item[in]
467 : : * Item specification. Only source and destination addresses and
468 : : * protocol fields are supported. If the mask is NULL, default
469 : : * mask will be used. Ranging is not supported.
470 : : * @param efx_spec[in, out]
471 : : * EFX filter specification to update.
472 : : * @param[out] error
473 : : * Perform verbose error reporting if not NULL.
474 : : */
475 : : static int
476 : 0 : sfc_flow_parse_ipv4(const struct rte_flow_item *item,
477 : : struct sfc_flow_parse_ctx *parse_ctx,
478 : : struct rte_flow_error *error)
479 : : {
480 : : int rc;
481 : 0 : efx_filter_spec_t *efx_spec = parse_ctx->filter;
482 : 0 : const struct rte_flow_item_ipv4 *spec = NULL;
483 : 0 : const struct rte_flow_item_ipv4 *mask = NULL;
484 : : const uint16_t ether_type_ipv4 = rte_cpu_to_le_16(EFX_ETHER_TYPE_IPV4);
485 : 0 : const struct rte_flow_item_ipv4 supp_mask = {
486 : : .hdr = {
487 : : .src_addr = 0xffffffff,
488 : : .dst_addr = 0xffffffff,
489 : : .next_proto_id = 0xff,
490 : : }
491 : : };
492 : :
493 : 0 : rc = sfc_flow_parse_init(item,
494 : : (const void **)&spec,
495 : : (const void **)&mask,
496 : : &supp_mask,
497 : : &rte_flow_item_ipv4_mask,
498 : : sizeof(struct rte_flow_item_ipv4),
499 : : error);
500 [ # # ]: 0 : if (rc != 0)
501 : : return rc;
502 : :
503 : : /*
504 : : * Filtering by IPv4 source and destination addresses requires
505 : : * the appropriate ETHER_TYPE in hardware filters
506 : : */
507 [ # # ]: 0 : if (!(efx_spec->efs_match_flags & EFX_FILTER_MATCH_ETHER_TYPE)) {
508 : 0 : efx_spec->efs_match_flags |= EFX_FILTER_MATCH_ETHER_TYPE;
509 : 0 : efx_spec->efs_ether_type = ether_type_ipv4;
510 [ # # ]: 0 : } else if (efx_spec->efs_ether_type != ether_type_ipv4) {
511 : 0 : rte_flow_error_set(error, EINVAL,
512 : : RTE_FLOW_ERROR_TYPE_ITEM, item,
513 : : "Ethertype in pattern with IPV4 item should be appropriate");
514 : 0 : return -rte_errno;
515 : : }
516 : :
517 [ # # ]: 0 : if (spec == NULL)
518 : : return 0;
519 : :
520 : : /*
521 : : * IPv4 addresses are in big-endian byte order in item and in
522 : : * efx_spec
523 : : */
524 [ # # ]: 0 : if (mask->hdr.src_addr == supp_mask.hdr.src_addr) {
525 : 0 : efx_spec->efs_match_flags |= EFX_FILTER_MATCH_REM_HOST;
526 : 0 : efx_spec->efs_rem_host.eo_u32[0] = spec->hdr.src_addr;
527 [ # # ]: 0 : } else if (mask->hdr.src_addr != 0) {
528 : 0 : goto fail_bad_mask;
529 : : }
530 : :
531 [ # # ]: 0 : if (mask->hdr.dst_addr == supp_mask.hdr.dst_addr) {
532 : 0 : efx_spec->efs_match_flags |= EFX_FILTER_MATCH_LOC_HOST;
533 : 0 : efx_spec->efs_loc_host.eo_u32[0] = spec->hdr.dst_addr;
534 [ # # ]: 0 : } else if (mask->hdr.dst_addr != 0) {
535 : 0 : goto fail_bad_mask;
536 : : }
537 : :
538 [ # # ]: 0 : if (mask->hdr.next_proto_id == supp_mask.hdr.next_proto_id) {
539 : 0 : efx_spec->efs_match_flags |= EFX_FILTER_MATCH_IP_PROTO;
540 : 0 : efx_spec->efs_ip_proto = spec->hdr.next_proto_id;
541 [ # # ]: 0 : } else if (mask->hdr.next_proto_id != 0) {
542 : 0 : goto fail_bad_mask;
543 : : }
544 : :
545 : : return 0;
546 : :
547 : 0 : fail_bad_mask:
548 : 0 : rte_flow_error_set(error, EINVAL,
549 : : RTE_FLOW_ERROR_TYPE_ITEM, item,
550 : : "Bad mask in the IPV4 pattern item");
551 : 0 : return -rte_errno;
552 : : }
553 : :
554 : : /**
555 : : * Convert IPv6 item to EFX filter specification.
556 : : *
557 : : * @param item[in]
558 : : * Item specification. Only source and destination addresses and
559 : : * next header fields are supported. If the mask is NULL, default
560 : : * mask will be used. Ranging is not supported.
561 : : * @param efx_spec[in, out]
562 : : * EFX filter specification to update.
563 : : * @param[out] error
564 : : * Perform verbose error reporting if not NULL.
565 : : */
566 : : static int
567 : 0 : sfc_flow_parse_ipv6(const struct rte_flow_item *item,
568 : : struct sfc_flow_parse_ctx *parse_ctx,
569 : : struct rte_flow_error *error)
570 : : {
571 : : int rc;
572 : 0 : efx_filter_spec_t *efx_spec = parse_ctx->filter;
573 : 0 : const struct rte_flow_item_ipv6 *spec = NULL;
574 : 0 : const struct rte_flow_item_ipv6 *mask = NULL;
575 : : const uint16_t ether_type_ipv6 = rte_cpu_to_le_16(EFX_ETHER_TYPE_IPV6);
576 : 0 : const struct rte_flow_item_ipv6 supp_mask = {
577 : : .hdr = {
578 : : .src_addr = { 0xff, 0xff, 0xff, 0xff,
579 : : 0xff, 0xff, 0xff, 0xff,
580 : : 0xff, 0xff, 0xff, 0xff,
581 : : 0xff, 0xff, 0xff, 0xff },
582 : : .dst_addr = { 0xff, 0xff, 0xff, 0xff,
583 : : 0xff, 0xff, 0xff, 0xff,
584 : : 0xff, 0xff, 0xff, 0xff,
585 : : 0xff, 0xff, 0xff, 0xff },
586 : : .proto = 0xff,
587 : : }
588 : : };
589 : :
590 : 0 : rc = sfc_flow_parse_init(item,
591 : : (const void **)&spec,
592 : : (const void **)&mask,
593 : : &supp_mask,
594 : : &rte_flow_item_ipv6_mask,
595 : : sizeof(struct rte_flow_item_ipv6),
596 : : error);
597 [ # # ]: 0 : if (rc != 0)
598 : : return rc;
599 : :
600 : : /*
601 : : * Filtering by IPv6 source and destination addresses requires
602 : : * the appropriate ETHER_TYPE in hardware filters
603 : : */
604 [ # # ]: 0 : if (!(efx_spec->efs_match_flags & EFX_FILTER_MATCH_ETHER_TYPE)) {
605 : 0 : efx_spec->efs_match_flags |= EFX_FILTER_MATCH_ETHER_TYPE;
606 : 0 : efx_spec->efs_ether_type = ether_type_ipv6;
607 [ # # ]: 0 : } else if (efx_spec->efs_ether_type != ether_type_ipv6) {
608 : 0 : rte_flow_error_set(error, EINVAL,
609 : : RTE_FLOW_ERROR_TYPE_ITEM, item,
610 : : "Ethertype in pattern with IPV6 item should be appropriate");
611 : 0 : return -rte_errno;
612 : : }
613 : :
614 [ # # ]: 0 : if (spec == NULL)
615 : : return 0;
616 : :
617 : : /*
618 : : * IPv6 addresses are in big-endian byte order in item and in
619 : : * efx_spec
620 : : */
621 [ # # ]: 0 : if (memcmp(mask->hdr.src_addr, supp_mask.hdr.src_addr,
622 : : sizeof(mask->hdr.src_addr)) == 0) {
623 : 0 : efx_spec->efs_match_flags |= EFX_FILTER_MATCH_REM_HOST;
624 : :
625 : : RTE_BUILD_BUG_ON(sizeof(efx_spec->efs_rem_host) !=
626 : : sizeof(spec->hdr.src_addr));
627 [ # # ]: 0 : rte_memcpy(&efx_spec->efs_rem_host, spec->hdr.src_addr,
628 : : sizeof(efx_spec->efs_rem_host));
629 [ # # ]: 0 : } else if (!sfc_flow_is_zero(mask->hdr.src_addr,
630 : : sizeof(mask->hdr.src_addr))) {
631 : 0 : goto fail_bad_mask;
632 : : }
633 : :
634 [ # # ]: 0 : if (memcmp(mask->hdr.dst_addr, supp_mask.hdr.dst_addr,
635 : : sizeof(mask->hdr.dst_addr)) == 0) {
636 : 0 : efx_spec->efs_match_flags |= EFX_FILTER_MATCH_LOC_HOST;
637 : :
638 : : RTE_BUILD_BUG_ON(sizeof(efx_spec->efs_loc_host) !=
639 : : sizeof(spec->hdr.dst_addr));
640 [ # # ]: 0 : rte_memcpy(&efx_spec->efs_loc_host, spec->hdr.dst_addr,
641 : : sizeof(efx_spec->efs_loc_host));
642 [ # # ]: 0 : } else if (!sfc_flow_is_zero(mask->hdr.dst_addr,
643 : : sizeof(mask->hdr.dst_addr))) {
644 : 0 : goto fail_bad_mask;
645 : : }
646 : :
647 [ # # ]: 0 : if (mask->hdr.proto == supp_mask.hdr.proto) {
648 : 0 : efx_spec->efs_match_flags |= EFX_FILTER_MATCH_IP_PROTO;
649 : 0 : efx_spec->efs_ip_proto = spec->hdr.proto;
650 [ # # ]: 0 : } else if (mask->hdr.proto != 0) {
651 : 0 : goto fail_bad_mask;
652 : : }
653 : :
654 : : return 0;
655 : :
656 : 0 : fail_bad_mask:
657 : 0 : rte_flow_error_set(error, EINVAL,
658 : : RTE_FLOW_ERROR_TYPE_ITEM, item,
659 : : "Bad mask in the IPV6 pattern item");
660 : 0 : return -rte_errno;
661 : : }
662 : :
663 : : /**
664 : : * Convert TCP item to EFX filter specification.
665 : : *
666 : : * @param item[in]
667 : : * Item specification. Only source and destination ports fields
668 : : * are supported. If the mask is NULL, default mask will be used.
669 : : * Ranging is not supported.
670 : : * @param efx_spec[in, out]
671 : : * EFX filter specification to update.
672 : : * @param[out] error
673 : : * Perform verbose error reporting if not NULL.
674 : : */
675 : : static int
676 : 0 : sfc_flow_parse_tcp(const struct rte_flow_item *item,
677 : : struct sfc_flow_parse_ctx *parse_ctx,
678 : : struct rte_flow_error *error)
679 : : {
680 : : int rc;
681 : 0 : efx_filter_spec_t *efx_spec = parse_ctx->filter;
682 : 0 : const struct rte_flow_item_tcp *spec = NULL;
683 : 0 : const struct rte_flow_item_tcp *mask = NULL;
684 : 0 : const struct rte_flow_item_tcp supp_mask = {
685 : : .hdr = {
686 : : .src_port = 0xffff,
687 : : .dst_port = 0xffff,
688 : : }
689 : : };
690 : :
691 : 0 : rc = sfc_flow_parse_init(item,
692 : : (const void **)&spec,
693 : : (const void **)&mask,
694 : : &supp_mask,
695 : : &rte_flow_item_tcp_mask,
696 : : sizeof(struct rte_flow_item_tcp),
697 : : error);
698 [ # # ]: 0 : if (rc != 0)
699 : : return rc;
700 : :
701 : : /*
702 : : * Filtering by TCP source and destination ports requires
703 : : * the appropriate IP_PROTO in hardware filters
704 : : */
705 [ # # ]: 0 : if (!(efx_spec->efs_match_flags & EFX_FILTER_MATCH_IP_PROTO)) {
706 : 0 : efx_spec->efs_match_flags |= EFX_FILTER_MATCH_IP_PROTO;
707 : 0 : efx_spec->efs_ip_proto = EFX_IPPROTO_TCP;
708 [ # # ]: 0 : } else if (efx_spec->efs_ip_proto != EFX_IPPROTO_TCP) {
709 : 0 : rte_flow_error_set(error, EINVAL,
710 : : RTE_FLOW_ERROR_TYPE_ITEM, item,
711 : : "IP proto in pattern with TCP item should be appropriate");
712 : 0 : return -rte_errno;
713 : : }
714 : :
715 [ # # ]: 0 : if (spec == NULL)
716 : : return 0;
717 : :
718 : : /*
719 : : * Source and destination ports are in big-endian byte order in item and
720 : : * in little-endian in efx_spec, so byte swap is used
721 : : */
722 [ # # ]: 0 : if (mask->hdr.src_port == supp_mask.hdr.src_port) {
723 : 0 : efx_spec->efs_match_flags |= EFX_FILTER_MATCH_REM_PORT;
724 [ # # ]: 0 : efx_spec->efs_rem_port = rte_bswap16(spec->hdr.src_port);
725 [ # # ]: 0 : } else if (mask->hdr.src_port != 0) {
726 : 0 : goto fail_bad_mask;
727 : : }
728 : :
729 [ # # ]: 0 : if (mask->hdr.dst_port == supp_mask.hdr.dst_port) {
730 : 0 : efx_spec->efs_match_flags |= EFX_FILTER_MATCH_LOC_PORT;
731 [ # # ]: 0 : efx_spec->efs_loc_port = rte_bswap16(spec->hdr.dst_port);
732 [ # # ]: 0 : } else if (mask->hdr.dst_port != 0) {
733 : 0 : goto fail_bad_mask;
734 : : }
735 : :
736 : : return 0;
737 : :
738 : 0 : fail_bad_mask:
739 : 0 : rte_flow_error_set(error, EINVAL,
740 : : RTE_FLOW_ERROR_TYPE_ITEM, item,
741 : : "Bad mask in the TCP pattern item");
742 : 0 : return -rte_errno;
743 : : }
744 : :
745 : : /**
746 : : * Convert UDP item to EFX filter specification.
747 : : *
748 : : * @param item[in]
749 : : * Item specification. Only source and destination ports fields
750 : : * are supported. If the mask is NULL, default mask will be used.
751 : : * Ranging is not supported.
752 : : * @param efx_spec[in, out]
753 : : * EFX filter specification to update.
754 : : * @param[out] error
755 : : * Perform verbose error reporting if not NULL.
756 : : */
757 : : static int
758 : 0 : sfc_flow_parse_udp(const struct rte_flow_item *item,
759 : : struct sfc_flow_parse_ctx *parse_ctx,
760 : : struct rte_flow_error *error)
761 : : {
762 : : int rc;
763 : 0 : efx_filter_spec_t *efx_spec = parse_ctx->filter;
764 : 0 : const struct rte_flow_item_udp *spec = NULL;
765 : 0 : const struct rte_flow_item_udp *mask = NULL;
766 : 0 : const struct rte_flow_item_udp supp_mask = {
767 : : .hdr = {
768 : : .src_port = 0xffff,
769 : : .dst_port = 0xffff,
770 : : }
771 : : };
772 : :
773 : 0 : rc = sfc_flow_parse_init(item,
774 : : (const void **)&spec,
775 : : (const void **)&mask,
776 : : &supp_mask,
777 : : &rte_flow_item_udp_mask,
778 : : sizeof(struct rte_flow_item_udp),
779 : : error);
780 [ # # ]: 0 : if (rc != 0)
781 : : return rc;
782 : :
783 : : /*
784 : : * Filtering by UDP source and destination ports requires
785 : : * the appropriate IP_PROTO in hardware filters
786 : : */
787 [ # # ]: 0 : if (!(efx_spec->efs_match_flags & EFX_FILTER_MATCH_IP_PROTO)) {
788 : 0 : efx_spec->efs_match_flags |= EFX_FILTER_MATCH_IP_PROTO;
789 : 0 : efx_spec->efs_ip_proto = EFX_IPPROTO_UDP;
790 [ # # ]: 0 : } else if (efx_spec->efs_ip_proto != EFX_IPPROTO_UDP) {
791 : 0 : rte_flow_error_set(error, EINVAL,
792 : : RTE_FLOW_ERROR_TYPE_ITEM, item,
793 : : "IP proto in pattern with UDP item should be appropriate");
794 : 0 : return -rte_errno;
795 : : }
796 : :
797 [ # # ]: 0 : if (spec == NULL)
798 : : return 0;
799 : :
800 : : /*
801 : : * Source and destination ports are in big-endian byte order in item and
802 : : * in little-endian in efx_spec, so byte swap is used
803 : : */
804 [ # # ]: 0 : if (mask->hdr.src_port == supp_mask.hdr.src_port) {
805 : 0 : efx_spec->efs_match_flags |= EFX_FILTER_MATCH_REM_PORT;
806 [ # # ]: 0 : efx_spec->efs_rem_port = rte_bswap16(spec->hdr.src_port);
807 [ # # ]: 0 : } else if (mask->hdr.src_port != 0) {
808 : 0 : goto fail_bad_mask;
809 : : }
810 : :
811 [ # # ]: 0 : if (mask->hdr.dst_port == supp_mask.hdr.dst_port) {
812 : 0 : efx_spec->efs_match_flags |= EFX_FILTER_MATCH_LOC_PORT;
813 [ # # ]: 0 : efx_spec->efs_loc_port = rte_bswap16(spec->hdr.dst_port);
814 [ # # ]: 0 : } else if (mask->hdr.dst_port != 0) {
815 : 0 : goto fail_bad_mask;
816 : : }
817 : :
818 : : return 0;
819 : :
820 : 0 : fail_bad_mask:
821 : 0 : rte_flow_error_set(error, EINVAL,
822 : : RTE_FLOW_ERROR_TYPE_ITEM, item,
823 : : "Bad mask in the UDP pattern item");
824 : 0 : return -rte_errno;
825 : : }
826 : :
827 : : /*
828 : : * Filters for encapsulated packets match based on the EtherType and IP
829 : : * protocol in the outer frame.
830 : : */
831 : : static int
832 : 0 : sfc_flow_set_match_flags_for_encap_pkts(const struct rte_flow_item *item,
833 : : efx_filter_spec_t *efx_spec,
834 : : uint8_t ip_proto,
835 : : struct rte_flow_error *error)
836 : : {
837 [ # # ]: 0 : if (!(efx_spec->efs_match_flags & EFX_FILTER_MATCH_IP_PROTO)) {
838 : 0 : efx_spec->efs_match_flags |= EFX_FILTER_MATCH_IP_PROTO;
839 : 0 : efx_spec->efs_ip_proto = ip_proto;
840 [ # # ]: 0 : } else if (efx_spec->efs_ip_proto != ip_proto) {
841 [ # # # ]: 0 : switch (ip_proto) {
842 : 0 : case EFX_IPPROTO_UDP:
843 : 0 : rte_flow_error_set(error, EINVAL,
844 : : RTE_FLOW_ERROR_TYPE_ITEM, item,
845 : : "Outer IP header protocol must be UDP "
846 : : "in VxLAN/GENEVE pattern");
847 : 0 : return -rte_errno;
848 : :
849 : 0 : case EFX_IPPROTO_GRE:
850 : 0 : rte_flow_error_set(error, EINVAL,
851 : : RTE_FLOW_ERROR_TYPE_ITEM, item,
852 : : "Outer IP header protocol must be GRE "
853 : : "in NVGRE pattern");
854 : 0 : return -rte_errno;
855 : :
856 : 0 : default:
857 : 0 : rte_flow_error_set(error, EINVAL,
858 : : RTE_FLOW_ERROR_TYPE_ITEM, item,
859 : : "Only VxLAN/GENEVE/NVGRE tunneling patterns "
860 : : "are supported");
861 : 0 : return -rte_errno;
862 : : }
863 : : }
864 : :
865 [ # # ]: 0 : if (efx_spec->efs_match_flags & EFX_FILTER_MATCH_ETHER_TYPE &&
866 [ # # # # ]: 0 : efx_spec->efs_ether_type != EFX_ETHER_TYPE_IPV4 &&
867 : : efx_spec->efs_ether_type != EFX_ETHER_TYPE_IPV6) {
868 : 0 : rte_flow_error_set(error, EINVAL,
869 : : RTE_FLOW_ERROR_TYPE_ITEM, item,
870 : : "Outer frame EtherType in pattern with tunneling "
871 : : "must be IPv4 or IPv6");
872 : 0 : return -rte_errno;
873 : : }
874 : :
875 : : return 0;
876 : : }
877 : :
878 : : static int
879 : 0 : sfc_flow_set_efx_spec_vni_or_vsid(efx_filter_spec_t *efx_spec,
880 : : const uint8_t *vni_or_vsid_val,
881 : : const uint8_t *vni_or_vsid_mask,
882 : : const struct rte_flow_item *item,
883 : : struct rte_flow_error *error)
884 : : {
885 : 0 : const uint8_t vni_or_vsid_full_mask[EFX_VNI_OR_VSID_LEN] = {
886 : : 0xff, 0xff, 0xff
887 : : };
888 : :
889 [ # # ]: 0 : if (memcmp(vni_or_vsid_mask, vni_or_vsid_full_mask,
890 : : EFX_VNI_OR_VSID_LEN) == 0) {
891 : 0 : efx_spec->efs_match_flags |= EFX_FILTER_MATCH_VNI_OR_VSID;
892 [ # # ]: 0 : rte_memcpy(efx_spec->efs_vni_or_vsid, vni_or_vsid_val,
893 : : EFX_VNI_OR_VSID_LEN);
894 [ # # ]: 0 : } else if (!sfc_flow_is_zero(vni_or_vsid_mask, EFX_VNI_OR_VSID_LEN)) {
895 : 0 : rte_flow_error_set(error, EINVAL,
896 : : RTE_FLOW_ERROR_TYPE_ITEM, item,
897 : : "Unsupported VNI/VSID mask");
898 : 0 : return -rte_errno;
899 : : }
900 : :
901 : : return 0;
902 : : }
903 : :
904 : : /**
905 : : * Convert VXLAN item to EFX filter specification.
906 : : *
907 : : * @param item[in]
908 : : * Item specification. Only VXLAN network identifier field is supported.
909 : : * If the mask is NULL, default mask will be used.
910 : : * Ranging is not supported.
911 : : * @param efx_spec[in, out]
912 : : * EFX filter specification to update.
913 : : * @param[out] error
914 : : * Perform verbose error reporting if not NULL.
915 : : */
916 : : static int
917 : 0 : sfc_flow_parse_vxlan(const struct rte_flow_item *item,
918 : : struct sfc_flow_parse_ctx *parse_ctx,
919 : : struct rte_flow_error *error)
920 : : {
921 : : int rc;
922 : 0 : efx_filter_spec_t *efx_spec = parse_ctx->filter;
923 : 0 : const struct rte_flow_item_vxlan *spec = NULL;
924 : 0 : const struct rte_flow_item_vxlan *mask = NULL;
925 : 0 : const struct rte_flow_item_vxlan supp_mask = {
926 : : .hdr.vni = { 0xff, 0xff, 0xff }
927 : : };
928 : :
929 : 0 : rc = sfc_flow_parse_init(item,
930 : : (const void **)&spec,
931 : : (const void **)&mask,
932 : : &supp_mask,
933 : : &rte_flow_item_vxlan_mask,
934 : : sizeof(struct rte_flow_item_vxlan),
935 : : error);
936 [ # # ]: 0 : if (rc != 0)
937 : : return rc;
938 : :
939 : 0 : rc = sfc_flow_set_match_flags_for_encap_pkts(item, efx_spec,
940 : : EFX_IPPROTO_UDP, error);
941 [ # # ]: 0 : if (rc != 0)
942 : : return rc;
943 : :
944 : 0 : efx_spec->efs_encap_type = EFX_TUNNEL_PROTOCOL_VXLAN;
945 : 0 : efx_spec->efs_match_flags |= EFX_FILTER_MATCH_ENCAP_TYPE;
946 : :
947 [ # # ]: 0 : if (spec == NULL)
948 : : return 0;
949 : :
950 : 0 : rc = sfc_flow_set_efx_spec_vni_or_vsid(efx_spec, spec->hdr.vni,
951 : 0 : mask->hdr.vni, item, error);
952 : :
953 : 0 : return rc;
954 : : }
955 : :
956 : : /**
957 : : * Convert GENEVE item to EFX filter specification.
958 : : *
959 : : * @param item[in]
960 : : * Item specification. Only Virtual Network Identifier and protocol type
961 : : * fields are supported. But protocol type can be only Ethernet (0x6558).
962 : : * If the mask is NULL, default mask will be used.
963 : : * Ranging is not supported.
964 : : * @param efx_spec[in, out]
965 : : * EFX filter specification to update.
966 : : * @param[out] error
967 : : * Perform verbose error reporting if not NULL.
968 : : */
969 : : static int
970 : 0 : sfc_flow_parse_geneve(const struct rte_flow_item *item,
971 : : struct sfc_flow_parse_ctx *parse_ctx,
972 : : struct rte_flow_error *error)
973 : : {
974 : : int rc;
975 : 0 : efx_filter_spec_t *efx_spec = parse_ctx->filter;
976 : 0 : const struct rte_flow_item_geneve *spec = NULL;
977 : 0 : const struct rte_flow_item_geneve *mask = NULL;
978 : 0 : const struct rte_flow_item_geneve supp_mask = {
979 : : .protocol = RTE_BE16(0xffff),
980 : : .vni = { 0xff, 0xff, 0xff }
981 : : };
982 : :
983 : 0 : rc = sfc_flow_parse_init(item,
984 : : (const void **)&spec,
985 : : (const void **)&mask,
986 : : &supp_mask,
987 : : &rte_flow_item_geneve_mask,
988 : : sizeof(struct rte_flow_item_geneve),
989 : : error);
990 [ # # ]: 0 : if (rc != 0)
991 : : return rc;
992 : :
993 : 0 : rc = sfc_flow_set_match_flags_for_encap_pkts(item, efx_spec,
994 : : EFX_IPPROTO_UDP, error);
995 [ # # ]: 0 : if (rc != 0)
996 : : return rc;
997 : :
998 : 0 : efx_spec->efs_encap_type = EFX_TUNNEL_PROTOCOL_GENEVE;
999 : 0 : efx_spec->efs_match_flags |= EFX_FILTER_MATCH_ENCAP_TYPE;
1000 : :
1001 [ # # ]: 0 : if (spec == NULL)
1002 : : return 0;
1003 : :
1004 [ # # ]: 0 : if (mask->protocol == supp_mask.protocol) {
1005 [ # # ]: 0 : if (spec->protocol != rte_cpu_to_be_16(RTE_ETHER_TYPE_TEB)) {
1006 : 0 : rte_flow_error_set(error, EINVAL,
1007 : : RTE_FLOW_ERROR_TYPE_ITEM, item,
1008 : : "GENEVE encap. protocol must be Ethernet "
1009 : : "(0x6558) in the GENEVE pattern item");
1010 : 0 : return -rte_errno;
1011 : : }
1012 [ # # ]: 0 : } else if (mask->protocol != 0) {
1013 : 0 : rte_flow_error_set(error, EINVAL,
1014 : : RTE_FLOW_ERROR_TYPE_ITEM, item,
1015 : : "Unsupported mask for GENEVE encap. protocol");
1016 : 0 : return -rte_errno;
1017 : : }
1018 : :
1019 : 0 : rc = sfc_flow_set_efx_spec_vni_or_vsid(efx_spec, spec->vni,
1020 : 0 : mask->vni, item, error);
1021 : :
1022 : 0 : return rc;
1023 : : }
1024 : :
1025 : : /**
1026 : : * Convert NVGRE item to EFX filter specification.
1027 : : *
1028 : : * @param item[in]
1029 : : * Item specification. Only virtual subnet ID field is supported.
1030 : : * If the mask is NULL, default mask will be used.
1031 : : * Ranging is not supported.
1032 : : * @param efx_spec[in, out]
1033 : : * EFX filter specification to update.
1034 : : * @param[out] error
1035 : : * Perform verbose error reporting if not NULL.
1036 : : */
1037 : : static int
1038 : 0 : sfc_flow_parse_nvgre(const struct rte_flow_item *item,
1039 : : struct sfc_flow_parse_ctx *parse_ctx,
1040 : : struct rte_flow_error *error)
1041 : : {
1042 : : int rc;
1043 : 0 : efx_filter_spec_t *efx_spec = parse_ctx->filter;
1044 : 0 : const struct rte_flow_item_nvgre *spec = NULL;
1045 : 0 : const struct rte_flow_item_nvgre *mask = NULL;
1046 : 0 : const struct rte_flow_item_nvgre supp_mask = {
1047 : : .tni = { 0xff, 0xff, 0xff }
1048 : : };
1049 : :
1050 : 0 : rc = sfc_flow_parse_init(item,
1051 : : (const void **)&spec,
1052 : : (const void **)&mask,
1053 : : &supp_mask,
1054 : : &rte_flow_item_nvgre_mask,
1055 : : sizeof(struct rte_flow_item_nvgre),
1056 : : error);
1057 [ # # ]: 0 : if (rc != 0)
1058 : : return rc;
1059 : :
1060 : 0 : rc = sfc_flow_set_match_flags_for_encap_pkts(item, efx_spec,
1061 : : EFX_IPPROTO_GRE, error);
1062 [ # # ]: 0 : if (rc != 0)
1063 : : return rc;
1064 : :
1065 : 0 : efx_spec->efs_encap_type = EFX_TUNNEL_PROTOCOL_NVGRE;
1066 : 0 : efx_spec->efs_match_flags |= EFX_FILTER_MATCH_ENCAP_TYPE;
1067 : :
1068 [ # # ]: 0 : if (spec == NULL)
1069 : : return 0;
1070 : :
1071 : 0 : rc = sfc_flow_set_efx_spec_vni_or_vsid(efx_spec, spec->tni,
1072 : 0 : mask->tni, item, error);
1073 : :
1074 : 0 : return rc;
1075 : : }
1076 : :
1077 : : /**
1078 : : * Convert PPPoEx item to EFX filter specification.
1079 : : *
1080 : : * @param item[in]
1081 : : * Item specification.
1082 : : * Matching on PPPoEx fields is not supported.
1083 : : * This item can only be used to set or validate the EtherType filter.
1084 : : * Only zero masks are allowed.
1085 : : * Ranging is not supported.
1086 : : * @param efx_spec[in, out]
1087 : : * EFX filter specification to update.
1088 : : * @param[out] error
1089 : : * Perform verbose error reporting if not NULL.
1090 : : */
1091 : : static int
1092 : 0 : sfc_flow_parse_pppoex(const struct rte_flow_item *item,
1093 : : struct sfc_flow_parse_ctx *parse_ctx,
1094 : : struct rte_flow_error *error)
1095 : : {
1096 : 0 : efx_filter_spec_t *efx_spec = parse_ctx->filter;
1097 : 0 : const struct rte_flow_item_pppoe *spec = NULL;
1098 : 0 : const struct rte_flow_item_pppoe *mask = NULL;
1099 : 0 : const struct rte_flow_item_pppoe supp_mask = {};
1100 : 0 : const struct rte_flow_item_pppoe def_mask = {};
1101 : : uint16_t ether_type;
1102 : : int rc;
1103 : :
1104 : 0 : rc = sfc_flow_parse_init(item,
1105 : : (const void **)&spec,
1106 : : (const void **)&mask,
1107 : : &supp_mask,
1108 : : &def_mask,
1109 : : sizeof(struct rte_flow_item_pppoe),
1110 : : error);
1111 [ # # ]: 0 : if (rc != 0)
1112 : : return rc;
1113 : :
1114 [ # # ]: 0 : if (item->type == RTE_FLOW_ITEM_TYPE_PPPOED)
1115 : : ether_type = RTE_ETHER_TYPE_PPPOE_DISCOVERY;
1116 : : else
1117 : : ether_type = RTE_ETHER_TYPE_PPPOE_SESSION;
1118 : :
1119 [ # # ]: 0 : if ((efx_spec->efs_match_flags & EFX_FILTER_MATCH_ETHER_TYPE) != 0) {
1120 [ # # ]: 0 : if (efx_spec->efs_ether_type != ether_type) {
1121 : 0 : rte_flow_error_set(error, EINVAL,
1122 : : RTE_FLOW_ERROR_TYPE_ITEM, item,
1123 : : "Invalid EtherType for a PPPoE flow item");
1124 : 0 : return -rte_errno;
1125 : : }
1126 : : } else {
1127 : 0 : efx_spec->efs_match_flags |= EFX_FILTER_MATCH_ETHER_TYPE;
1128 : 0 : efx_spec->efs_ether_type = ether_type;
1129 : : }
1130 : :
1131 : : return 0;
1132 : : }
1133 : :
1134 : : static const struct sfc_flow_item sfc_flow_items[] = {
1135 : : {
1136 : : .type = RTE_FLOW_ITEM_TYPE_VOID,
1137 : : .name = "VOID",
1138 : : .prev_layer = SFC_FLOW_ITEM_ANY_LAYER,
1139 : : .layer = SFC_FLOW_ITEM_ANY_LAYER,
1140 : : .ctx_type = SFC_FLOW_PARSE_CTX_FILTER,
1141 : : .parse = sfc_flow_parse_void,
1142 : : },
1143 : : {
1144 : : .type = RTE_FLOW_ITEM_TYPE_ETH,
1145 : : .name = "ETH",
1146 : : .prev_layer = SFC_FLOW_ITEM_START_LAYER,
1147 : : .layer = SFC_FLOW_ITEM_L2,
1148 : : .ctx_type = SFC_FLOW_PARSE_CTX_FILTER,
1149 : : .parse = sfc_flow_parse_eth,
1150 : : },
1151 : : {
1152 : : .type = RTE_FLOW_ITEM_TYPE_VLAN,
1153 : : .name = "VLAN",
1154 : : .prev_layer = SFC_FLOW_ITEM_L2,
1155 : : .layer = SFC_FLOW_ITEM_L2,
1156 : : .ctx_type = SFC_FLOW_PARSE_CTX_FILTER,
1157 : : .parse = sfc_flow_parse_vlan,
1158 : : },
1159 : : {
1160 : : .type = RTE_FLOW_ITEM_TYPE_PPPOED,
1161 : : .name = "PPPOED",
1162 : : .prev_layer = SFC_FLOW_ITEM_L2,
1163 : : .layer = SFC_FLOW_ITEM_L2,
1164 : : .ctx_type = SFC_FLOW_PARSE_CTX_FILTER,
1165 : : .parse = sfc_flow_parse_pppoex,
1166 : : },
1167 : : {
1168 : : .type = RTE_FLOW_ITEM_TYPE_PPPOES,
1169 : : .name = "PPPOES",
1170 : : .prev_layer = SFC_FLOW_ITEM_L2,
1171 : : .layer = SFC_FLOW_ITEM_L2,
1172 : : .ctx_type = SFC_FLOW_PARSE_CTX_FILTER,
1173 : : .parse = sfc_flow_parse_pppoex,
1174 : : },
1175 : : {
1176 : : .type = RTE_FLOW_ITEM_TYPE_IPV4,
1177 : : .name = "IPV4",
1178 : : .prev_layer = SFC_FLOW_ITEM_L2,
1179 : : .layer = SFC_FLOW_ITEM_L3,
1180 : : .ctx_type = SFC_FLOW_PARSE_CTX_FILTER,
1181 : : .parse = sfc_flow_parse_ipv4,
1182 : : },
1183 : : {
1184 : : .type = RTE_FLOW_ITEM_TYPE_IPV6,
1185 : : .name = "IPV6",
1186 : : .prev_layer = SFC_FLOW_ITEM_L2,
1187 : : .layer = SFC_FLOW_ITEM_L3,
1188 : : .ctx_type = SFC_FLOW_PARSE_CTX_FILTER,
1189 : : .parse = sfc_flow_parse_ipv6,
1190 : : },
1191 : : {
1192 : : .type = RTE_FLOW_ITEM_TYPE_TCP,
1193 : : .name = "TCP",
1194 : : .prev_layer = SFC_FLOW_ITEM_L3,
1195 : : .layer = SFC_FLOW_ITEM_L4,
1196 : : .ctx_type = SFC_FLOW_PARSE_CTX_FILTER,
1197 : : .parse = sfc_flow_parse_tcp,
1198 : : },
1199 : : {
1200 : : .type = RTE_FLOW_ITEM_TYPE_UDP,
1201 : : .name = "UDP",
1202 : : .prev_layer = SFC_FLOW_ITEM_L3,
1203 : : .layer = SFC_FLOW_ITEM_L4,
1204 : : .ctx_type = SFC_FLOW_PARSE_CTX_FILTER,
1205 : : .parse = sfc_flow_parse_udp,
1206 : : },
1207 : : {
1208 : : .type = RTE_FLOW_ITEM_TYPE_VXLAN,
1209 : : .name = "VXLAN",
1210 : : .prev_layer = SFC_FLOW_ITEM_L4,
1211 : : .layer = SFC_FLOW_ITEM_START_LAYER,
1212 : : .ctx_type = SFC_FLOW_PARSE_CTX_FILTER,
1213 : : .parse = sfc_flow_parse_vxlan,
1214 : : },
1215 : : {
1216 : : .type = RTE_FLOW_ITEM_TYPE_GENEVE,
1217 : : .name = "GENEVE",
1218 : : .prev_layer = SFC_FLOW_ITEM_L4,
1219 : : .layer = SFC_FLOW_ITEM_START_LAYER,
1220 : : .ctx_type = SFC_FLOW_PARSE_CTX_FILTER,
1221 : : .parse = sfc_flow_parse_geneve,
1222 : : },
1223 : : {
1224 : : .type = RTE_FLOW_ITEM_TYPE_NVGRE,
1225 : : .name = "NVGRE",
1226 : : .prev_layer = SFC_FLOW_ITEM_L3,
1227 : : .layer = SFC_FLOW_ITEM_START_LAYER,
1228 : : .ctx_type = SFC_FLOW_PARSE_CTX_FILTER,
1229 : : .parse = sfc_flow_parse_nvgre,
1230 : : },
1231 : : };
1232 : :
1233 : : /*
1234 : : * Protocol-independent flow API support
1235 : : */
1236 : : static int
1237 : 0 : sfc_flow_parse_attr(struct sfc_adapter *sa,
1238 : : const struct rte_flow_attr *attr,
1239 : : struct rte_flow *flow,
1240 : : struct rte_flow_error *error)
1241 : : {
1242 : : struct sfc_flow_spec *spec = &flow->spec;
1243 : : struct sfc_flow_spec_filter *spec_filter = &spec->filter;
1244 : : struct sfc_flow_spec_mae *spec_mae = &spec->mae;
1245 : : struct sfc_mae *mae = &sa->mae;
1246 : :
1247 [ # # ]: 0 : if (attr == NULL) {
1248 : 0 : rte_flow_error_set(error, EINVAL,
1249 : : RTE_FLOW_ERROR_TYPE_ATTR, NULL,
1250 : : "NULL attribute");
1251 : 0 : return -rte_errno;
1252 : : }
1253 [ # # ]: 0 : if (attr->group != 0) {
1254 : 0 : rte_flow_error_set(error, ENOTSUP,
1255 : : RTE_FLOW_ERROR_TYPE_ATTR_GROUP, attr,
1256 : : "Groups are not supported");
1257 : 0 : return -rte_errno;
1258 : : }
1259 [ # # ]: 0 : if (attr->egress != 0 && attr->transfer == 0) {
1260 : 0 : rte_flow_error_set(error, ENOTSUP,
1261 : : RTE_FLOW_ERROR_TYPE_ATTR_EGRESS, attr,
1262 : : "Egress is not supported");
1263 : 0 : return -rte_errno;
1264 : : }
1265 [ # # ]: 0 : if (attr->ingress == 0 && attr->transfer == 0) {
1266 : 0 : rte_flow_error_set(error, ENOTSUP,
1267 : : RTE_FLOW_ERROR_TYPE_ATTR_INGRESS, attr,
1268 : : "Ingress is compulsory");
1269 : 0 : return -rte_errno;
1270 : : }
1271 [ # # ]: 0 : if (attr->transfer == 0) {
1272 [ # # ]: 0 : if (attr->priority != 0) {
1273 : 0 : rte_flow_error_set(error, ENOTSUP,
1274 : : RTE_FLOW_ERROR_TYPE_ATTR_PRIORITY,
1275 : : attr, "Priorities are unsupported");
1276 : 0 : return -rte_errno;
1277 : : }
1278 : 0 : spec->type = SFC_FLOW_SPEC_FILTER;
1279 : 0 : spec_filter->template.efs_flags |= EFX_FILTER_FLAG_RX;
1280 : 0 : spec_filter->template.efs_rss_context = EFX_RSS_CONTEXT_DEFAULT;
1281 : 0 : spec_filter->template.efs_priority = EFX_FILTER_PRI_MANUAL;
1282 : : } else {
1283 [ # # ]: 0 : if (mae->status != SFC_MAE_STATUS_ADMIN) {
1284 : 0 : rte_flow_error_set(error, ENOTSUP,
1285 : : RTE_FLOW_ERROR_TYPE_ATTR_TRANSFER,
1286 : : attr, "Transfer is not supported");
1287 : 0 : return -rte_errno;
1288 : : }
1289 [ # # ]: 0 : if (attr->priority > mae->nb_action_rule_prios_max) {
1290 : 0 : rte_flow_error_set(error, ENOTSUP,
1291 : : RTE_FLOW_ERROR_TYPE_ATTR_PRIORITY,
1292 : : attr, "Unsupported priority level");
1293 : 0 : return -rte_errno;
1294 : : }
1295 : 0 : spec->type = SFC_FLOW_SPEC_MAE;
1296 : 0 : spec_mae->priority = attr->priority;
1297 : 0 : spec_mae->action_rule = NULL;
1298 : : }
1299 : :
1300 : : return 0;
1301 : : }
1302 : :
1303 : : /* Get item from array sfc_flow_items */
1304 : : static const struct sfc_flow_item *
1305 : : sfc_flow_get_item(const struct sfc_flow_item *items,
1306 : : unsigned int nb_items,
1307 : : enum rte_flow_item_type type)
1308 : : {
1309 : : unsigned int i;
1310 : :
1311 [ # # ]: 0 : for (i = 0; i < nb_items; i++)
1312 [ # # ]: 0 : if (items[i].type == type)
1313 : : return &items[i];
1314 : :
1315 : : return NULL;
1316 : : }
1317 : :
1318 : : int
1319 : 0 : sfc_flow_parse_pattern(struct sfc_adapter *sa,
1320 : : const struct sfc_flow_item *flow_items,
1321 : : unsigned int nb_flow_items,
1322 : : const struct rte_flow_item pattern[],
1323 : : struct sfc_flow_parse_ctx *parse_ctx,
1324 : : struct rte_flow_error *error)
1325 : : {
1326 : : int rc;
1327 : : unsigned int prev_layer = SFC_FLOW_ITEM_ANY_LAYER;
1328 : : boolean_t is_ifrm = B_FALSE;
1329 : : const struct sfc_flow_item *item;
1330 : :
1331 [ # # ]: 0 : if (pattern == NULL) {
1332 : 0 : rte_flow_error_set(error, EINVAL,
1333 : : RTE_FLOW_ERROR_TYPE_ITEM_NUM, NULL,
1334 : : "NULL pattern");
1335 : 0 : return -rte_errno;
1336 : : }
1337 : :
1338 [ # # ]: 0 : for (; pattern->type != RTE_FLOW_ITEM_TYPE_END; pattern++) {
1339 : : item = sfc_flow_get_item(flow_items, nb_flow_items,
1340 : : pattern->type);
1341 [ # # ]: 0 : if (item == NULL) {
1342 : 0 : rte_flow_error_set(error, ENOTSUP,
1343 : : RTE_FLOW_ERROR_TYPE_ITEM, pattern,
1344 : : "Unsupported pattern item");
1345 : 0 : return -rte_errno;
1346 : : }
1347 : :
1348 : : /*
1349 : : * Omitting one or several protocol layers at the beginning
1350 : : * of pattern is supported
1351 : : */
1352 [ # # # # ]: 0 : if (item->prev_layer != SFC_FLOW_ITEM_ANY_LAYER &&
1353 [ # # ]: 0 : prev_layer != SFC_FLOW_ITEM_ANY_LAYER &&
1354 : : item->prev_layer != prev_layer) {
1355 : 0 : rte_flow_error_set(error, ENOTSUP,
1356 : : RTE_FLOW_ERROR_TYPE_ITEM, pattern,
1357 : : "Unexpected sequence of pattern items");
1358 : 0 : return -rte_errno;
1359 : : }
1360 : :
1361 : : /*
1362 : : * Allow only VOID and ETH pattern items in the inner frame.
1363 : : * Also check that there is only one tunneling protocol.
1364 : : */
1365 [ # # # ]: 0 : switch (item->type) {
1366 : : case RTE_FLOW_ITEM_TYPE_VOID:
1367 : : case RTE_FLOW_ITEM_TYPE_ETH:
1368 : : break;
1369 : :
1370 : 0 : case RTE_FLOW_ITEM_TYPE_VXLAN:
1371 : : case RTE_FLOW_ITEM_TYPE_GENEVE:
1372 : : case RTE_FLOW_ITEM_TYPE_NVGRE:
1373 [ # # ]: 0 : if (is_ifrm) {
1374 : 0 : rte_flow_error_set(error, EINVAL,
1375 : : RTE_FLOW_ERROR_TYPE_ITEM,
1376 : : pattern,
1377 : : "More than one tunneling protocol");
1378 : 0 : return -rte_errno;
1379 : : }
1380 : : is_ifrm = B_TRUE;
1381 : : break;
1382 : :
1383 : 0 : default:
1384 [ # # # # ]: 0 : if (parse_ctx->type == SFC_FLOW_PARSE_CTX_FILTER &&
1385 : : is_ifrm) {
1386 : 0 : rte_flow_error_set(error, EINVAL,
1387 : : RTE_FLOW_ERROR_TYPE_ITEM,
1388 : : pattern,
1389 : : "There is an unsupported pattern item "
1390 : : "in the inner frame");
1391 : 0 : return -rte_errno;
1392 : : }
1393 : : break;
1394 : : }
1395 : :
1396 [ # # ]: 0 : if (parse_ctx->type != item->ctx_type) {
1397 : 0 : rte_flow_error_set(error, EINVAL,
1398 : : RTE_FLOW_ERROR_TYPE_ITEM, pattern,
1399 : : "Parse context type mismatch");
1400 : 0 : return -rte_errno;
1401 : : }
1402 : :
1403 : 0 : rc = item->parse(pattern, parse_ctx, error);
1404 [ # # ]: 0 : if (rc != 0) {
1405 : 0 : sfc_err(sa, "failed to parse item %s: %s",
1406 : : item->name, strerror(-rc));
1407 : 0 : return rc;
1408 : : }
1409 : :
1410 [ # # ]: 0 : if (item->layer != SFC_FLOW_ITEM_ANY_LAYER)
1411 : : prev_layer = item->layer;
1412 : : }
1413 : :
1414 : : return 0;
1415 : : }
1416 : :
1417 : : static int
1418 : 0 : sfc_flow_parse_queue(struct sfc_adapter *sa,
1419 : : const struct rte_flow_action_queue *queue,
1420 : : struct rte_flow *flow)
1421 : : {
1422 : : struct sfc_flow_spec *spec = &flow->spec;
1423 : : struct sfc_flow_spec_filter *spec_filter = &spec->filter;
1424 : : struct sfc_rxq *rxq;
1425 : : struct sfc_rxq_info *rxq_info;
1426 : :
1427 [ # # ]: 0 : if (queue->index >= sfc_sa2shared(sa)->ethdev_rxq_count)
1428 : : return -EINVAL;
1429 : :
1430 : 0 : rxq = sfc_rxq_ctrl_by_ethdev_qid(sa, queue->index);
1431 [ # # ]: 0 : spec_filter->template.efs_dmaq_id = (uint16_t)rxq->hw_index;
1432 : :
1433 : 0 : rxq_info = &sfc_sa2shared(sa)->rxq_info[queue->index];
1434 : :
1435 [ # # ]: 0 : if ((rxq_info->rxq_flags & SFC_RXQ_FLAG_RSS_HASH) != 0) {
1436 : : struct sfc_adapter_shared * const sas = sfc_sa2shared(sa);
1437 : : struct sfc_rss *ethdev_rss = &sas->rss;
1438 : :
1439 : 0 : spec_filter->template.efs_flags |= EFX_FILTER_FLAG_RX_RSS;
1440 : 0 : spec_filter->rss_ctx = ðdev_rss->dummy_ctx;
1441 : : }
1442 : :
1443 : : return 0;
1444 : : }
1445 : :
1446 : : static int
1447 : 0 : sfc_flow_parse_rss(struct sfc_adapter *sa,
1448 : : const struct rte_flow_action_rss *action_rss,
1449 : : struct rte_flow *flow)
1450 : : {
1451 : : struct sfc_flow_spec_filter *spec_filter = &flow->spec.filter;
1452 : : struct sfc_flow_rss_conf conf;
1453 : : uint16_t sw_qid_min;
1454 : : struct sfc_rxq *rxq;
1455 : : int rc;
1456 : :
1457 : 0 : spec_filter->template.efs_flags |= EFX_FILTER_FLAG_RX_RSS;
1458 : :
1459 : 0 : rc = sfc_flow_rss_parse_conf(sa, action_rss, &conf, &sw_qid_min);
1460 [ # # ]: 0 : if (rc != 0)
1461 : 0 : return -rc;
1462 : :
1463 : 0 : rxq = sfc_rxq_ctrl_by_ethdev_qid(sa, sw_qid_min);
1464 : 0 : spec_filter->template.efs_dmaq_id = rxq->hw_index;
1465 : :
1466 : 0 : spec_filter->rss_ctx = sfc_flow_rss_ctx_reuse(sa, &conf, sw_qid_min,
1467 : 0 : action_rss->queue);
1468 [ # # ]: 0 : if (spec_filter->rss_ctx != NULL)
1469 : : return 0;
1470 : :
1471 : 0 : rc = sfc_flow_rss_ctx_add(sa, &conf, sw_qid_min, action_rss->queue,
1472 : : &spec_filter->rss_ctx);
1473 [ # # ]: 0 : if (rc != 0)
1474 : 0 : return -rc;
1475 : :
1476 : : return 0;
1477 : : }
1478 : :
1479 : : static int
1480 : 0 : sfc_flow_spec_flush(struct sfc_adapter *sa, struct sfc_flow_spec *spec,
1481 : : unsigned int filters_count)
1482 : : {
1483 : : struct sfc_flow_spec_filter *spec_filter = &spec->filter;
1484 : : unsigned int i;
1485 : : int ret = 0;
1486 : :
1487 [ # # ]: 0 : for (i = 0; i < filters_count; i++) {
1488 : : int rc;
1489 : :
1490 : 0 : rc = efx_filter_remove(sa->nic, &spec_filter->filters[i]);
1491 [ # # ]: 0 : if (ret == 0 && rc != 0) {
1492 : 0 : sfc_err(sa, "failed to remove filter specification "
1493 : : "(rc = %d)", rc);
1494 : : ret = rc;
1495 : : }
1496 : : }
1497 : :
1498 : 0 : return ret;
1499 : : }
1500 : :
1501 : : static int
1502 : 0 : sfc_flow_spec_insert(struct sfc_adapter *sa, struct sfc_flow_spec *spec)
1503 : : {
1504 : : struct sfc_flow_spec_filter *spec_filter = &spec->filter;
1505 : : unsigned int i;
1506 : : int rc = 0;
1507 : :
1508 [ # # ]: 0 : for (i = 0; i < spec_filter->count; i++) {
1509 : 0 : rc = efx_filter_insert(sa->nic, &spec_filter->filters[i]);
1510 [ # # ]: 0 : if (rc != 0) {
1511 : 0 : sfc_flow_spec_flush(sa, spec, i);
1512 : 0 : break;
1513 : : }
1514 : : }
1515 : :
1516 : 0 : return rc;
1517 : : }
1518 : :
1519 : : static int
1520 : : sfc_flow_spec_remove(struct sfc_adapter *sa, struct sfc_flow_spec *spec)
1521 : : {
1522 : : struct sfc_flow_spec_filter *spec_filter = &spec->filter;
1523 : :
1524 : 0 : return sfc_flow_spec_flush(sa, spec, spec_filter->count);
1525 : : }
1526 : :
1527 : : static int
1528 : 0 : sfc_flow_filter_insert(struct sfc_adapter *sa,
1529 : : struct rte_flow *flow)
1530 : : {
1531 : : struct sfc_flow_spec_filter *spec_filter = &flow->spec.filter;
1532 : 0 : struct sfc_flow_rss_ctx *rss_ctx = spec_filter->rss_ctx;
1533 : : int rc = 0;
1534 : :
1535 : 0 : rc = sfc_flow_rss_ctx_program(sa, rss_ctx);
1536 [ # # ]: 0 : if (rc != 0)
1537 : 0 : goto fail_rss_ctx_program;
1538 : :
1539 [ # # ]: 0 : if (rss_ctx != NULL) {
1540 : : unsigned int i;
1541 : :
1542 : : /*
1543 : : * At this point, fully elaborated filter specifications
1544 : : * have been produced from the template. To make sure that
1545 : : * RSS behaviour is consistent between them, set the same
1546 : : * RSS context value everywhere.
1547 : : */
1548 [ # # ]: 0 : for (i = 0; i < spec_filter->count; i++) {
1549 : : efx_filter_spec_t *spec = &spec_filter->filters[i];
1550 : :
1551 : 0 : spec->efs_rss_context = rss_ctx->nic_handle;
1552 : : }
1553 : : }
1554 : :
1555 : 0 : rc = sfc_flow_spec_insert(sa, &flow->spec);
1556 [ # # ]: 0 : if (rc != 0)
1557 : 0 : goto fail_filter_insert;
1558 : :
1559 : : return 0;
1560 : :
1561 : : fail_filter_insert:
1562 : 0 : sfc_flow_rss_ctx_terminate(sa, rss_ctx);
1563 : :
1564 : : fail_rss_ctx_program:
1565 : : return rc;
1566 : : }
1567 : :
1568 : : static int
1569 : 0 : sfc_flow_filter_remove(struct sfc_adapter *sa,
1570 : : struct rte_flow *flow)
1571 : : {
1572 : : struct sfc_flow_spec_filter *spec_filter = &flow->spec.filter;
1573 : : int rc = 0;
1574 : :
1575 : 0 : rc = sfc_flow_spec_remove(sa, &flow->spec);
1576 [ # # ]: 0 : if (rc != 0)
1577 : : return rc;
1578 : :
1579 : 0 : sfc_flow_rss_ctx_terminate(sa, spec_filter->rss_ctx);
1580 : :
1581 : 0 : return 0;
1582 : : }
1583 : :
1584 : : static int
1585 : 0 : sfc_flow_parse_mark(struct sfc_adapter *sa,
1586 : : const struct rte_flow_action_mark *mark,
1587 : : struct rte_flow *flow)
1588 : : {
1589 : : struct sfc_flow_spec *spec = &flow->spec;
1590 : : struct sfc_flow_spec_filter *spec_filter = &spec->filter;
1591 : 0 : const efx_nic_cfg_t *encp = efx_nic_cfg_get(sa->nic);
1592 : : uint32_t mark_max;
1593 : :
1594 : 0 : mark_max = encp->enc_filter_action_mark_max;
1595 [ # # ]: 0 : if (sfc_ft_is_active(sa))
1596 : 0 : mark_max = RTE_MIN(mark_max, SFC_FT_USER_MARK_MASK);
1597 : :
1598 [ # # # # ]: 0 : if (mark == NULL || mark->id > mark_max)
1599 : : return EINVAL;
1600 : :
1601 : 0 : spec_filter->template.efs_flags |= EFX_FILTER_FLAG_ACTION_MARK;
1602 : 0 : spec_filter->template.efs_mark = mark->id;
1603 : :
1604 : 0 : return 0;
1605 : : }
1606 : :
1607 : : static int
1608 : 0 : sfc_flow_parse_actions(struct sfc_adapter *sa,
1609 : : const struct rte_flow_action actions[],
1610 : : struct rte_flow *flow,
1611 : : struct rte_flow_error *error)
1612 : : {
1613 : : int rc;
1614 : : struct sfc_flow_spec *spec = &flow->spec;
1615 : : struct sfc_flow_spec_filter *spec_filter = &spec->filter;
1616 : 0 : const unsigned int dp_rx_features = sa->priv.dp_rx->features;
1617 : 0 : const uint64_t rx_metadata = sa->negotiated_rx_metadata;
1618 : : uint32_t actions_set = 0;
1619 : : const uint32_t fate_actions_mask = (1UL << RTE_FLOW_ACTION_TYPE_QUEUE) |
1620 : : (1UL << RTE_FLOW_ACTION_TYPE_RSS) |
1621 : : (1UL << RTE_FLOW_ACTION_TYPE_DROP);
1622 : : const uint32_t mark_actions_mask = (1UL << RTE_FLOW_ACTION_TYPE_MARK) |
1623 : : (1UL << RTE_FLOW_ACTION_TYPE_FLAG);
1624 : :
1625 [ # # ]: 0 : if (actions == NULL) {
1626 : 0 : rte_flow_error_set(error, EINVAL,
1627 : : RTE_FLOW_ERROR_TYPE_ACTION_NUM, NULL,
1628 : : "NULL actions");
1629 : 0 : return -rte_errno;
1630 : : }
1631 : :
1632 [ # # ]: 0 : for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) {
1633 [ # # # # : 0 : switch (actions->type) {
# # # ]
1634 : : case RTE_FLOW_ACTION_TYPE_VOID:
1635 : : SFC_BUILD_SET_OVERFLOW(RTE_FLOW_ACTION_TYPE_VOID,
1636 : : actions_set);
1637 : : break;
1638 : :
1639 : 0 : case RTE_FLOW_ACTION_TYPE_QUEUE:
1640 : : SFC_BUILD_SET_OVERFLOW(RTE_FLOW_ACTION_TYPE_QUEUE,
1641 : : actions_set);
1642 [ # # ]: 0 : if ((actions_set & fate_actions_mask) != 0)
1643 : 0 : goto fail_fate_actions;
1644 : :
1645 : 0 : rc = sfc_flow_parse_queue(sa, actions->conf, flow);
1646 [ # # ]: 0 : if (rc != 0) {
1647 : 0 : rte_flow_error_set(error, EINVAL,
1648 : : RTE_FLOW_ERROR_TYPE_ACTION, actions,
1649 : : "Bad QUEUE action");
1650 : 0 : return -rte_errno;
1651 : : }
1652 : : break;
1653 : :
1654 : 0 : case RTE_FLOW_ACTION_TYPE_RSS:
1655 : : SFC_BUILD_SET_OVERFLOW(RTE_FLOW_ACTION_TYPE_RSS,
1656 : : actions_set);
1657 [ # # ]: 0 : if ((actions_set & fate_actions_mask) != 0)
1658 : 0 : goto fail_fate_actions;
1659 : :
1660 : 0 : rc = sfc_flow_parse_rss(sa, actions->conf, flow);
1661 [ # # ]: 0 : if (rc != 0) {
1662 : 0 : rte_flow_error_set(error, -rc,
1663 : : RTE_FLOW_ERROR_TYPE_ACTION, actions,
1664 : : "Bad RSS action");
1665 : 0 : return -rte_errno;
1666 : : }
1667 : : break;
1668 : :
1669 : 0 : case RTE_FLOW_ACTION_TYPE_DROP:
1670 : : SFC_BUILD_SET_OVERFLOW(RTE_FLOW_ACTION_TYPE_DROP,
1671 : : actions_set);
1672 [ # # ]: 0 : if ((actions_set & fate_actions_mask) != 0)
1673 : 0 : goto fail_fate_actions;
1674 : :
1675 : 0 : spec_filter->template.efs_dmaq_id =
1676 : : EFX_FILTER_SPEC_RX_DMAQ_ID_DROP;
1677 : 0 : break;
1678 : :
1679 : 0 : case RTE_FLOW_ACTION_TYPE_FLAG:
1680 : : SFC_BUILD_SET_OVERFLOW(RTE_FLOW_ACTION_TYPE_FLAG,
1681 : : actions_set);
1682 [ # # ]: 0 : if ((actions_set & mark_actions_mask) != 0)
1683 : 0 : goto fail_actions_overlap;
1684 : :
1685 [ # # ]: 0 : if ((dp_rx_features & SFC_DP_RX_FEAT_FLOW_FLAG) == 0) {
1686 : 0 : rte_flow_error_set(error, ENOTSUP,
1687 : : RTE_FLOW_ERROR_TYPE_ACTION, NULL,
1688 : : "FLAG action is not supported on the current Rx datapath");
1689 : 0 : return -rte_errno;
1690 [ # # ]: 0 : } else if ((rx_metadata &
1691 : : RTE_ETH_RX_METADATA_USER_FLAG) == 0) {
1692 : 0 : rte_flow_error_set(error, ENOTSUP,
1693 : : RTE_FLOW_ERROR_TYPE_ACTION, NULL,
1694 : : "flag delivery has not been negotiated");
1695 : 0 : return -rte_errno;
1696 : : }
1697 : :
1698 : 0 : spec_filter->template.efs_flags |=
1699 : : EFX_FILTER_FLAG_ACTION_FLAG;
1700 : 0 : break;
1701 : :
1702 : 0 : case RTE_FLOW_ACTION_TYPE_MARK:
1703 : : SFC_BUILD_SET_OVERFLOW(RTE_FLOW_ACTION_TYPE_MARK,
1704 : : actions_set);
1705 [ # # ]: 0 : if ((actions_set & mark_actions_mask) != 0)
1706 : 0 : goto fail_actions_overlap;
1707 : :
1708 [ # # ]: 0 : if ((dp_rx_features & SFC_DP_RX_FEAT_FLOW_MARK) == 0) {
1709 : 0 : rte_flow_error_set(error, ENOTSUP,
1710 : : RTE_FLOW_ERROR_TYPE_ACTION, NULL,
1711 : : "MARK action is not supported on the current Rx datapath");
1712 : 0 : return -rte_errno;
1713 [ # # ]: 0 : } else if ((rx_metadata &
1714 : : RTE_ETH_RX_METADATA_USER_MARK) == 0) {
1715 : 0 : rte_flow_error_set(error, ENOTSUP,
1716 : : RTE_FLOW_ERROR_TYPE_ACTION, NULL,
1717 : : "mark delivery has not been negotiated");
1718 : 0 : return -rte_errno;
1719 : : }
1720 : :
1721 : 0 : rc = sfc_flow_parse_mark(sa, actions->conf, flow);
1722 [ # # ]: 0 : if (rc != 0) {
1723 : 0 : rte_flow_error_set(error, rc,
1724 : : RTE_FLOW_ERROR_TYPE_ACTION, actions,
1725 : : "Bad MARK action");
1726 : 0 : return -rte_errno;
1727 : : }
1728 : : break;
1729 : :
1730 : 0 : default:
1731 : 0 : rte_flow_error_set(error, ENOTSUP,
1732 : : RTE_FLOW_ERROR_TYPE_ACTION, actions,
1733 : : "Action is not supported");
1734 : 0 : return -rte_errno;
1735 : : }
1736 : :
1737 : 0 : actions_set |= (1UL << actions->type);
1738 : : }
1739 : :
1740 : : /* When fate is unknown, drop traffic. */
1741 [ # # ]: 0 : if ((actions_set & fate_actions_mask) == 0) {
1742 : 0 : spec_filter->template.efs_dmaq_id =
1743 : : EFX_FILTER_SPEC_RX_DMAQ_ID_DROP;
1744 : : }
1745 : :
1746 : : return 0;
1747 : :
1748 : 0 : fail_fate_actions:
1749 : 0 : rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION, actions,
1750 : : "Cannot combine several fate-deciding actions, "
1751 : : "choose between QUEUE, RSS or DROP");
1752 : 0 : return -rte_errno;
1753 : :
1754 : 0 : fail_actions_overlap:
1755 : 0 : rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION, actions,
1756 : : "Overlapping actions are not supported");
1757 : 0 : return -rte_errno;
1758 : : }
1759 : :
1760 : : /**
1761 : : * Set the EFX_FILTER_MATCH_UNKNOWN_UCAST_DST
1762 : : * and EFX_FILTER_MATCH_UNKNOWN_MCAST_DST match flags in the same
1763 : : * specifications after copying.
1764 : : *
1765 : : * @param spec[in, out]
1766 : : * SFC flow specification to update.
1767 : : * @param filters_count_for_one_val[in]
1768 : : * How many specifications should have the same match flag, what is the
1769 : : * number of specifications before copying.
1770 : : * @param error[out]
1771 : : * Perform verbose error reporting if not NULL.
1772 : : */
1773 : : static int
1774 : 0 : sfc_flow_set_unknown_dst_flags(struct sfc_flow_spec *spec,
1775 : : unsigned int filters_count_for_one_val,
1776 : : struct rte_flow_error *error)
1777 : : {
1778 : : unsigned int i;
1779 : : struct sfc_flow_spec_filter *spec_filter = &spec->filter;
1780 : : static const efx_filter_match_flags_t vals[] = {
1781 : : EFX_FILTER_MATCH_UNKNOWN_UCAST_DST,
1782 : : EFX_FILTER_MATCH_UNKNOWN_MCAST_DST
1783 : : };
1784 : :
1785 [ # # ]: 0 : if (filters_count_for_one_val * RTE_DIM(vals) != spec_filter->count) {
1786 : 0 : rte_flow_error_set(error, EINVAL,
1787 : : RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
1788 : : "Number of specifications is incorrect while copying "
1789 : : "by unknown destination flags");
1790 : 0 : return -rte_errno;
1791 : : }
1792 : :
1793 [ # # ]: 0 : for (i = 0; i < spec_filter->count; i++) {
1794 : : /* The check above ensures that divisor can't be zero here */
1795 : 0 : spec_filter->filters[i].efs_match_flags |=
1796 : 0 : vals[i / filters_count_for_one_val];
1797 : : }
1798 : :
1799 : : return 0;
1800 : : }
1801 : :
1802 : : /**
1803 : : * Check that the following conditions are met:
1804 : : * - the list of supported filters has a filter
1805 : : * with EFX_FILTER_MATCH_UNKNOWN_MCAST_DST flag instead of
1806 : : * EFX_FILTER_MATCH_UNKNOWN_UCAST_DST, since this filter will also
1807 : : * be inserted.
1808 : : *
1809 : : * @param match[in]
1810 : : * The match flags of filter.
1811 : : * @param spec[in]
1812 : : * Specification to be supplemented.
1813 : : * @param filter[in]
1814 : : * SFC filter with list of supported filters.
1815 : : */
1816 : : static boolean_t
1817 : 0 : sfc_flow_check_unknown_dst_flags(efx_filter_match_flags_t match,
1818 : : __rte_unused efx_filter_spec_t *spec,
1819 : : struct sfc_filter *filter)
1820 : : {
1821 : : unsigned int i;
1822 : : efx_filter_match_flags_t match_mcast_dst;
1823 : :
1824 : 0 : match_mcast_dst =
1825 : 0 : (match & ~EFX_FILTER_MATCH_UNKNOWN_UCAST_DST) |
1826 : : EFX_FILTER_MATCH_UNKNOWN_MCAST_DST;
1827 [ # # ]: 0 : for (i = 0; i < filter->supported_match_num; i++) {
1828 [ # # ]: 0 : if (match_mcast_dst == filter->supported_match[i])
1829 : : return B_TRUE;
1830 : : }
1831 : :
1832 : : return B_FALSE;
1833 : : }
1834 : :
1835 : : /**
1836 : : * Set the EFX_FILTER_MATCH_ETHER_TYPE match flag and EFX_ETHER_TYPE_IPV4 and
1837 : : * EFX_ETHER_TYPE_IPV6 values of the corresponding field in the same
1838 : : * specifications after copying.
1839 : : *
1840 : : * @param spec[in, out]
1841 : : * SFC flow specification to update.
1842 : : * @param filters_count_for_one_val[in]
1843 : : * How many specifications should have the same EtherType value, what is the
1844 : : * number of specifications before copying.
1845 : : * @param error[out]
1846 : : * Perform verbose error reporting if not NULL.
1847 : : */
1848 : : static int
1849 : 0 : sfc_flow_set_ethertypes(struct sfc_flow_spec *spec,
1850 : : unsigned int filters_count_for_one_val,
1851 : : struct rte_flow_error *error)
1852 : : {
1853 : : unsigned int i;
1854 : : struct sfc_flow_spec_filter *spec_filter = &spec->filter;
1855 : : static const uint16_t vals[] = {
1856 : : EFX_ETHER_TYPE_IPV4, EFX_ETHER_TYPE_IPV6
1857 : : };
1858 : :
1859 [ # # ]: 0 : if (filters_count_for_one_val * RTE_DIM(vals) != spec_filter->count) {
1860 : 0 : rte_flow_error_set(error, EINVAL,
1861 : : RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
1862 : : "Number of specifications is incorrect "
1863 : : "while copying by Ethertype");
1864 : 0 : return -rte_errno;
1865 : : }
1866 : :
1867 [ # # ]: 0 : for (i = 0; i < spec_filter->count; i++) {
1868 : 0 : spec_filter->filters[i].efs_match_flags |=
1869 : : EFX_FILTER_MATCH_ETHER_TYPE;
1870 : :
1871 : : /*
1872 : : * The check above ensures that
1873 : : * filters_count_for_one_val is not 0
1874 : : */
1875 : 0 : spec_filter->filters[i].efs_ether_type =
1876 : 0 : vals[i / filters_count_for_one_val];
1877 : : }
1878 : :
1879 : : return 0;
1880 : : }
1881 : :
1882 : : /**
1883 : : * Set the EFX_FILTER_MATCH_OUTER_VID match flag with value 0
1884 : : * in the same specifications after copying.
1885 : : *
1886 : : * @param spec[in, out]
1887 : : * SFC flow specification to update.
1888 : : * @param filters_count_for_one_val[in]
1889 : : * How many specifications should have the same match flag, what is the
1890 : : * number of specifications before copying.
1891 : : * @param error[out]
1892 : : * Perform verbose error reporting if not NULL.
1893 : : */
1894 : : static int
1895 : 0 : sfc_flow_set_outer_vid_flag(struct sfc_flow_spec *spec,
1896 : : unsigned int filters_count_for_one_val,
1897 : : struct rte_flow_error *error)
1898 : : {
1899 : : struct sfc_flow_spec_filter *spec_filter = &spec->filter;
1900 : : unsigned int i;
1901 : :
1902 [ # # ]: 0 : if (filters_count_for_one_val != spec_filter->count) {
1903 : 0 : rte_flow_error_set(error, EINVAL,
1904 : : RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
1905 : : "Number of specifications is incorrect "
1906 : : "while copying by outer VLAN ID");
1907 : 0 : return -rte_errno;
1908 : : }
1909 : :
1910 [ # # ]: 0 : for (i = 0; i < spec_filter->count; i++) {
1911 : 0 : spec_filter->filters[i].efs_match_flags |=
1912 : : EFX_FILTER_MATCH_OUTER_VID;
1913 : :
1914 : 0 : spec_filter->filters[i].efs_outer_vid = 0;
1915 : : }
1916 : :
1917 : : return 0;
1918 : : }
1919 : :
1920 : : /**
1921 : : * Set the EFX_FILTER_MATCH_IFRM_UNKNOWN_UCAST_DST and
1922 : : * EFX_FILTER_MATCH_IFRM_UNKNOWN_MCAST_DST match flags in the same
1923 : : * specifications after copying.
1924 : : *
1925 : : * @param spec[in, out]
1926 : : * SFC flow specification to update.
1927 : : * @param filters_count_for_one_val[in]
1928 : : * How many specifications should have the same match flag, what is the
1929 : : * number of specifications before copying.
1930 : : * @param error[out]
1931 : : * Perform verbose error reporting if not NULL.
1932 : : */
1933 : : static int
1934 : 0 : sfc_flow_set_ifrm_unknown_dst_flags(struct sfc_flow_spec *spec,
1935 : : unsigned int filters_count_for_one_val,
1936 : : struct rte_flow_error *error)
1937 : : {
1938 : : unsigned int i;
1939 : : struct sfc_flow_spec_filter *spec_filter = &spec->filter;
1940 : : static const efx_filter_match_flags_t vals[] = {
1941 : : EFX_FILTER_MATCH_IFRM_UNKNOWN_UCAST_DST,
1942 : : EFX_FILTER_MATCH_IFRM_UNKNOWN_MCAST_DST
1943 : : };
1944 : :
1945 [ # # ]: 0 : if (filters_count_for_one_val * RTE_DIM(vals) != spec_filter->count) {
1946 : 0 : rte_flow_error_set(error, EINVAL,
1947 : : RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
1948 : : "Number of specifications is incorrect while copying "
1949 : : "by inner frame unknown destination flags");
1950 : 0 : return -rte_errno;
1951 : : }
1952 : :
1953 [ # # ]: 0 : for (i = 0; i < spec_filter->count; i++) {
1954 : : /* The check above ensures that divisor can't be zero here */
1955 : 0 : spec_filter->filters[i].efs_match_flags |=
1956 : 0 : vals[i / filters_count_for_one_val];
1957 : : }
1958 : :
1959 : : return 0;
1960 : : }
1961 : :
1962 : : /**
1963 : : * Check that the following conditions are met:
1964 : : * - the specification corresponds to a filter for encapsulated traffic
1965 : : * - the list of supported filters has a filter
1966 : : * with EFX_FILTER_MATCH_IFRM_UNKNOWN_MCAST_DST flag instead of
1967 : : * EFX_FILTER_MATCH_IFRM_UNKNOWN_UCAST_DST, since this filter will also
1968 : : * be inserted.
1969 : : *
1970 : : * @param match[in]
1971 : : * The match flags of filter.
1972 : : * @param spec[in]
1973 : : * Specification to be supplemented.
1974 : : * @param filter[in]
1975 : : * SFC filter with list of supported filters.
1976 : : */
1977 : : static boolean_t
1978 : 0 : sfc_flow_check_ifrm_unknown_dst_flags(efx_filter_match_flags_t match,
1979 : : efx_filter_spec_t *spec,
1980 : : struct sfc_filter *filter)
1981 : : {
1982 : : unsigned int i;
1983 : 0 : efx_tunnel_protocol_t encap_type = spec->efs_encap_type;
1984 : : efx_filter_match_flags_t match_mcast_dst;
1985 : :
1986 [ # # ]: 0 : if (encap_type == EFX_TUNNEL_PROTOCOL_NONE)
1987 : : return B_FALSE;
1988 : :
1989 : 0 : match_mcast_dst =
1990 : 0 : (match & ~EFX_FILTER_MATCH_IFRM_UNKNOWN_UCAST_DST) |
1991 : : EFX_FILTER_MATCH_IFRM_UNKNOWN_MCAST_DST;
1992 [ # # ]: 0 : for (i = 0; i < filter->supported_match_num; i++) {
1993 [ # # ]: 0 : if (match_mcast_dst == filter->supported_match[i])
1994 : : return B_TRUE;
1995 : : }
1996 : :
1997 : : return B_FALSE;
1998 : : }
1999 : :
2000 : : /**
2001 : : * Check that the list of supported filters has a filter that differs
2002 : : * from @p match in that it has no flag EFX_FILTER_MATCH_OUTER_VID
2003 : : * in this case that filter will be used and the flag
2004 : : * EFX_FILTER_MATCH_OUTER_VID is not needed.
2005 : : *
2006 : : * @param match[in]
2007 : : * The match flags of filter.
2008 : : * @param spec[in]
2009 : : * Specification to be supplemented.
2010 : : * @param filter[in]
2011 : : * SFC filter with list of supported filters.
2012 : : */
2013 : : static boolean_t
2014 : 0 : sfc_flow_check_outer_vid_flag(efx_filter_match_flags_t match,
2015 : : __rte_unused efx_filter_spec_t *spec,
2016 : : struct sfc_filter *filter)
2017 : : {
2018 : : unsigned int i;
2019 : 0 : efx_filter_match_flags_t match_without_vid =
2020 : : match & ~EFX_FILTER_MATCH_OUTER_VID;
2021 : :
2022 [ # # ]: 0 : for (i = 0; i < filter->supported_match_num; i++) {
2023 [ # # ]: 0 : if (match_without_vid == filter->supported_match[i])
2024 : : return B_FALSE;
2025 : : }
2026 : :
2027 : : return B_TRUE;
2028 : : }
2029 : :
2030 : : /*
2031 : : * Match flags that can be automatically added to filters.
2032 : : * Selecting the last minimum when searching for the copy flag ensures that the
2033 : : * EFX_FILTER_MATCH_UNKNOWN_UCAST_DST flag has a higher priority than
2034 : : * EFX_FILTER_MATCH_ETHER_TYPE. This is because the filter
2035 : : * EFX_FILTER_MATCH_UNKNOWN_UCAST_DST is at the end of the list of supported
2036 : : * filters.
2037 : : */
2038 : : static const struct sfc_flow_copy_flag sfc_flow_copy_flags[] = {
2039 : : {
2040 : : .flag = EFX_FILTER_MATCH_UNKNOWN_UCAST_DST,
2041 : : .vals_count = 2,
2042 : : .set_vals = sfc_flow_set_unknown_dst_flags,
2043 : : .spec_check = sfc_flow_check_unknown_dst_flags,
2044 : : },
2045 : : {
2046 : : .flag = EFX_FILTER_MATCH_ETHER_TYPE,
2047 : : .vals_count = 2,
2048 : : .set_vals = sfc_flow_set_ethertypes,
2049 : : .spec_check = NULL,
2050 : : },
2051 : : {
2052 : : .flag = EFX_FILTER_MATCH_IFRM_UNKNOWN_UCAST_DST,
2053 : : .vals_count = 2,
2054 : : .set_vals = sfc_flow_set_ifrm_unknown_dst_flags,
2055 : : .spec_check = sfc_flow_check_ifrm_unknown_dst_flags,
2056 : : },
2057 : : {
2058 : : .flag = EFX_FILTER_MATCH_OUTER_VID,
2059 : : .vals_count = 1,
2060 : : .set_vals = sfc_flow_set_outer_vid_flag,
2061 : : .spec_check = sfc_flow_check_outer_vid_flag,
2062 : : },
2063 : : };
2064 : :
2065 : : /* Get item from array sfc_flow_copy_flags */
2066 : : static const struct sfc_flow_copy_flag *
2067 : : sfc_flow_get_copy_flag(efx_filter_match_flags_t flag)
2068 : : {
2069 : : unsigned int i;
2070 : :
2071 [ # # ]: 0 : for (i = 0; i < RTE_DIM(sfc_flow_copy_flags); i++) {
2072 [ # # ]: 0 : if (sfc_flow_copy_flags[i].flag == flag)
2073 : 0 : return &sfc_flow_copy_flags[i];
2074 : : }
2075 : :
2076 : : return NULL;
2077 : : }
2078 : :
2079 : : /**
2080 : : * Make copies of the specifications, set match flag and values
2081 : : * of the field that corresponds to it.
2082 : : *
2083 : : * @param spec[in, out]
2084 : : * SFC flow specification to update.
2085 : : * @param flag[in]
2086 : : * The match flag to add.
2087 : : * @param error[out]
2088 : : * Perform verbose error reporting if not NULL.
2089 : : */
2090 : : static int
2091 : 0 : sfc_flow_spec_add_match_flag(struct sfc_flow_spec *spec,
2092 : : efx_filter_match_flags_t flag,
2093 : : struct rte_flow_error *error)
2094 : : {
2095 : : unsigned int i;
2096 : : unsigned int new_filters_count;
2097 : : unsigned int filters_count_for_one_val;
2098 : : const struct sfc_flow_copy_flag *copy_flag;
2099 : : struct sfc_flow_spec_filter *spec_filter = &spec->filter;
2100 : : int rc;
2101 : :
2102 : : copy_flag = sfc_flow_get_copy_flag(flag);
2103 [ # # ]: 0 : if (copy_flag == NULL) {
2104 : 0 : rte_flow_error_set(error, ENOTSUP,
2105 : : RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
2106 : : "Unsupported spec field for copying");
2107 : 0 : return -rte_errno;
2108 : : }
2109 : :
2110 : 0 : new_filters_count = spec_filter->count * copy_flag->vals_count;
2111 [ # # ]: 0 : if (new_filters_count > SF_FLOW_SPEC_NB_FILTERS_MAX) {
2112 : 0 : rte_flow_error_set(error, EINVAL,
2113 : : RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
2114 : : "Too much EFX specifications in the flow rule");
2115 : 0 : return -rte_errno;
2116 : : }
2117 : :
2118 : : /* Copy filters specifications */
2119 [ # # ]: 0 : for (i = spec_filter->count; i < new_filters_count; i++) {
2120 : 0 : spec_filter->filters[i] =
2121 : 0 : spec_filter->filters[i - spec_filter->count];
2122 : : }
2123 : :
2124 : : filters_count_for_one_val = spec_filter->count;
2125 : 0 : spec_filter->count = new_filters_count;
2126 : :
2127 : 0 : rc = copy_flag->set_vals(spec, filters_count_for_one_val, error);
2128 [ # # ]: 0 : if (rc != 0)
2129 : 0 : return rc;
2130 : :
2131 : : return 0;
2132 : : }
2133 : :
2134 : : /**
2135 : : * Check that the given set of match flags missing in the original filter spec
2136 : : * could be covered by adding spec copies which specify the corresponding
2137 : : * flags and packet field values to match.
2138 : : *
2139 : : * @param miss_flags[in]
2140 : : * Flags that are missing until the supported filter.
2141 : : * @param spec[in]
2142 : : * Specification to be supplemented.
2143 : : * @param filter[in]
2144 : : * SFC filter.
2145 : : *
2146 : : * @return
2147 : : * Number of specifications after copy or 0, if the flags can not be added.
2148 : : */
2149 : : static unsigned int
2150 : 0 : sfc_flow_check_missing_flags(efx_filter_match_flags_t miss_flags,
2151 : : efx_filter_spec_t *spec,
2152 : : struct sfc_filter *filter)
2153 : : {
2154 : : unsigned int i;
2155 : : efx_filter_match_flags_t copy_flags = 0;
2156 : : efx_filter_match_flags_t flag;
2157 : 0 : efx_filter_match_flags_t match = spec->efs_match_flags | miss_flags;
2158 : : sfc_flow_spec_check *check;
2159 : : unsigned int multiplier = 1;
2160 : :
2161 [ # # ]: 0 : for (i = 0; i < RTE_DIM(sfc_flow_copy_flags); i++) {
2162 : 0 : flag = sfc_flow_copy_flags[i].flag;
2163 : 0 : check = sfc_flow_copy_flags[i].spec_check;
2164 [ # # ]: 0 : if ((flag & miss_flags) == flag) {
2165 [ # # # # ]: 0 : if (check != NULL && (!check(match, spec, filter)))
2166 : 0 : continue;
2167 : :
2168 : 0 : copy_flags |= flag;
2169 : 0 : multiplier *= sfc_flow_copy_flags[i].vals_count;
2170 : : }
2171 : : }
2172 : :
2173 [ # # ]: 0 : if (copy_flags == miss_flags)
2174 : 0 : return multiplier;
2175 : :
2176 : : return 0;
2177 : : }
2178 : :
2179 : : /**
2180 : : * Attempt to supplement the specification template to the minimally
2181 : : * supported set of match flags. To do this, it is necessary to copy
2182 : : * the specifications, filling them with the values of fields that
2183 : : * correspond to the missing flags.
2184 : : * The necessary and sufficient filter is built from the fewest number
2185 : : * of copies which could be made to cover the minimally required set
2186 : : * of flags.
2187 : : *
2188 : : * @param sa[in]
2189 : : * SFC adapter.
2190 : : * @param spec[in, out]
2191 : : * SFC flow specification to update.
2192 : : * @param error[out]
2193 : : * Perform verbose error reporting if not NULL.
2194 : : */
2195 : : static int
2196 : 0 : sfc_flow_spec_filters_complete(struct sfc_adapter *sa,
2197 : : struct sfc_flow_spec *spec,
2198 : : struct rte_flow_error *error)
2199 : : {
2200 : : struct sfc_flow_spec_filter *spec_filter = &spec->filter;
2201 : 0 : struct sfc_filter *filter = &sa->filter;
2202 : : efx_filter_match_flags_t miss_flags;
2203 : : efx_filter_match_flags_t min_miss_flags = 0;
2204 : : efx_filter_match_flags_t match;
2205 : : unsigned int min_multiplier = UINT_MAX;
2206 : : unsigned int multiplier;
2207 : : unsigned int i;
2208 : : int rc;
2209 : :
2210 : 0 : match = spec_filter->template.efs_match_flags;
2211 [ # # ]: 0 : for (i = 0; i < filter->supported_match_num; i++) {
2212 [ # # ]: 0 : if ((match & filter->supported_match[i]) == match) {
2213 : 0 : miss_flags = filter->supported_match[i] & (~match);
2214 : 0 : multiplier = sfc_flow_check_missing_flags(miss_flags,
2215 : : &spec_filter->template, filter);
2216 [ # # ]: 0 : if (multiplier > 0) {
2217 [ # # ]: 0 : if (multiplier <= min_multiplier) {
2218 : : min_multiplier = multiplier;
2219 : : min_miss_flags = miss_flags;
2220 : : }
2221 : : }
2222 : : }
2223 : : }
2224 : :
2225 [ # # ]: 0 : if (min_multiplier == UINT_MAX) {
2226 : 0 : rte_flow_error_set(error, ENOTSUP,
2227 : : RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
2228 : : "The flow rule pattern is unsupported");
2229 : 0 : return -rte_errno;
2230 : : }
2231 : :
2232 [ # # ]: 0 : for (i = 0; i < RTE_DIM(sfc_flow_copy_flags); i++) {
2233 : 0 : efx_filter_match_flags_t flag = sfc_flow_copy_flags[i].flag;
2234 : :
2235 [ # # ]: 0 : if ((flag & min_miss_flags) == flag) {
2236 : 0 : rc = sfc_flow_spec_add_match_flag(spec, flag, error);
2237 [ # # ]: 0 : if (rc != 0)
2238 : 0 : return rc;
2239 : : }
2240 : : }
2241 : :
2242 : : return 0;
2243 : : }
2244 : :
2245 : : /**
2246 : : * Check that set of match flags is referred to by a filter. Filter is
2247 : : * described by match flags with the ability to add OUTER_VID and INNER_VID
2248 : : * flags.
2249 : : *
2250 : : * @param match_flags[in]
2251 : : * Set of match flags.
2252 : : * @param flags_pattern[in]
2253 : : * Pattern of filter match flags.
2254 : : */
2255 : : static boolean_t
2256 : : sfc_flow_is_match_with_vids(efx_filter_match_flags_t match_flags,
2257 : : efx_filter_match_flags_t flags_pattern)
2258 : : {
2259 [ # # # # : 0 : if ((match_flags & flags_pattern) != flags_pattern)
# # ]
2260 : : return B_FALSE;
2261 : :
2262 [ # # # # : 0 : switch (match_flags & ~flags_pattern) {
# # # # ]
2263 : : case 0:
2264 : : case EFX_FILTER_MATCH_OUTER_VID:
2265 : : case EFX_FILTER_MATCH_OUTER_VID | EFX_FILTER_MATCH_INNER_VID:
2266 : : return B_TRUE;
2267 : : default:
2268 : : return B_FALSE;
2269 : : }
2270 : : }
2271 : :
2272 : : /**
2273 : : * Check whether the spec maps to a hardware filter which is known to be
2274 : : * ineffective despite being valid.
2275 : : *
2276 : : * @param filter[in]
2277 : : * SFC filter with list of supported filters.
2278 : : * @param spec[in]
2279 : : * SFC flow specification.
2280 : : */
2281 : : static boolean_t
2282 : 0 : sfc_flow_is_match_flags_exception(struct sfc_filter *filter,
2283 : : struct sfc_flow_spec *spec)
2284 : : {
2285 : : unsigned int i;
2286 : : uint16_t ether_type;
2287 : : uint8_t ip_proto;
2288 : : efx_filter_match_flags_t match_flags;
2289 : : struct sfc_flow_spec_filter *spec_filter = &spec->filter;
2290 : :
2291 [ # # ]: 0 : for (i = 0; i < spec_filter->count; i++) {
2292 [ # # ]: 0 : match_flags = spec_filter->filters[i].efs_match_flags;
2293 : :
2294 : : if (sfc_flow_is_match_with_vids(match_flags,
2295 : : EFX_FILTER_MATCH_ETHER_TYPE) ||
2296 : : sfc_flow_is_match_with_vids(match_flags,
2297 : : EFX_FILTER_MATCH_ETHER_TYPE |
2298 : : EFX_FILTER_MATCH_LOC_MAC)) {
2299 : 0 : ether_type = spec_filter->filters[i].efs_ether_type;
2300 [ # # ]: 0 : if (filter->supports_ip_proto_or_addr_filter &&
2301 : 0 : (ether_type == EFX_ETHER_TYPE_IPV4 ||
2302 [ # # ]: 0 : ether_type == EFX_ETHER_TYPE_IPV6))
2303 : : return B_TRUE;
2304 : : } else if (sfc_flow_is_match_with_vids(match_flags,
2305 : : EFX_FILTER_MATCH_ETHER_TYPE |
2306 : : EFX_FILTER_MATCH_IP_PROTO) ||
2307 : : sfc_flow_is_match_with_vids(match_flags,
2308 : : EFX_FILTER_MATCH_ETHER_TYPE |
2309 : : EFX_FILTER_MATCH_IP_PROTO |
2310 : : EFX_FILTER_MATCH_LOC_MAC)) {
2311 : 0 : ip_proto = spec_filter->filters[i].efs_ip_proto;
2312 [ # # ]: 0 : if (filter->supports_rem_or_local_port_filter &&
2313 : 0 : (ip_proto == EFX_IPPROTO_TCP ||
2314 [ # # ]: 0 : ip_proto == EFX_IPPROTO_UDP))
2315 : : return B_TRUE;
2316 : : }
2317 : : }
2318 : :
2319 : : return B_FALSE;
2320 : : }
2321 : :
2322 : : static int
2323 : 0 : sfc_flow_validate_match_flags(struct sfc_adapter *sa,
2324 : : struct rte_flow *flow,
2325 : : struct rte_flow_error *error)
2326 : : {
2327 : : struct sfc_flow_spec *spec = &flow->spec;
2328 : : struct sfc_flow_spec_filter *spec_filter = &spec->filter;
2329 : : efx_filter_spec_t *spec_tmpl = &spec_filter->template;
2330 : 0 : efx_filter_match_flags_t match_flags = spec_tmpl->efs_match_flags;
2331 : : int rc;
2332 : :
2333 : : /* Initialize the first filter spec with template */
2334 : 0 : spec_filter->filters[0] = *spec_tmpl;
2335 : 0 : spec_filter->count = 1;
2336 : :
2337 [ # # ]: 0 : if (!sfc_filter_is_match_supported(sa, match_flags)) {
2338 : 0 : rc = sfc_flow_spec_filters_complete(sa, &flow->spec, error);
2339 [ # # ]: 0 : if (rc != 0)
2340 : : return rc;
2341 : : }
2342 : :
2343 [ # # ]: 0 : if (sfc_flow_is_match_flags_exception(&sa->filter, &flow->spec)) {
2344 : 0 : rte_flow_error_set(error, ENOTSUP,
2345 : : RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
2346 : : "The flow rule pattern is unsupported");
2347 : 0 : return -rte_errno;
2348 : : }
2349 : :
2350 : : return 0;
2351 : : }
2352 : :
2353 : : static int
2354 : 0 : sfc_flow_parse_rte_to_filter(struct rte_eth_dev *dev,
2355 : : const struct rte_flow_item pattern[],
2356 : : const struct rte_flow_action actions[],
2357 : : struct rte_flow *flow,
2358 : : struct rte_flow_error *error)
2359 : : {
2360 : : struct sfc_adapter *sa = sfc_adapter_by_eth_dev(dev);
2361 : : struct sfc_flow_spec *spec = &flow->spec;
2362 : : struct sfc_flow_spec_filter *spec_filter = &spec->filter;
2363 : : struct sfc_flow_parse_ctx ctx;
2364 : : int rc;
2365 : :
2366 : 0 : ctx.type = SFC_FLOW_PARSE_CTX_FILTER;
2367 : 0 : ctx.filter = &spec_filter->template;
2368 : :
2369 : 0 : rc = sfc_flow_parse_pattern(sa, sfc_flow_items, RTE_DIM(sfc_flow_items),
2370 : : pattern, &ctx, error);
2371 [ # # ]: 0 : if (rc != 0)
2372 : 0 : goto fail_bad_value;
2373 : :
2374 : 0 : rc = sfc_flow_parse_actions(sa, actions, flow, error);
2375 [ # # ]: 0 : if (rc != 0)
2376 : 0 : goto fail_bad_value;
2377 : :
2378 : 0 : rc = sfc_flow_validate_match_flags(sa, flow, error);
2379 [ # # ]: 0 : if (rc != 0)
2380 : 0 : goto fail_bad_value;
2381 : :
2382 : : return 0;
2383 : :
2384 : : fail_bad_value:
2385 : : return rc;
2386 : : }
2387 : :
2388 : : static int
2389 : 0 : sfc_flow_parse_rte_to_mae(struct rte_eth_dev *dev,
2390 : : const struct rte_flow_item pattern[],
2391 : : const struct rte_flow_action actions[],
2392 : : struct rte_flow *flow,
2393 : : struct rte_flow_error *error)
2394 : : {
2395 : : struct sfc_adapter *sa = sfc_adapter_by_eth_dev(dev);
2396 : :
2397 : 0 : return sfc_mae_rule_parse(sa, pattern, actions, flow, error);
2398 : : }
2399 : :
2400 : : static int
2401 : 0 : sfc_flow_parse(struct rte_eth_dev *dev,
2402 : : const struct rte_flow_attr *attr,
2403 : : const struct rte_flow_item pattern[],
2404 : : const struct rte_flow_action actions[],
2405 : : struct rte_flow *flow,
2406 : : struct rte_flow_error *error)
2407 : : {
2408 : : struct sfc_adapter *sa = sfc_adapter_by_eth_dev(dev);
2409 : : const struct sfc_flow_ops_by_spec *ops;
2410 : : int rc;
2411 : :
2412 : 0 : rc = sfc_flow_parse_attr(sa, attr, flow, error);
2413 [ # # ]: 0 : if (rc != 0)
2414 : : return rc;
2415 : :
2416 : : ops = sfc_flow_get_ops_by_spec(flow);
2417 [ # # ]: 0 : if (ops == NULL || ops->parse == NULL) {
2418 : 0 : rte_flow_error_set(error, ENOTSUP,
2419 : : RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
2420 : : "No backend to handle this flow");
2421 : 0 : return -rte_errno;
2422 : : }
2423 : :
2424 : 0 : return ops->parse(dev, pattern, actions, flow, error);
2425 : : }
2426 : :
2427 : : static struct rte_flow *
2428 : 0 : sfc_flow_zmalloc(struct rte_flow_error *error)
2429 : : {
2430 : : struct rte_flow *flow;
2431 : :
2432 : 0 : flow = rte_zmalloc("sfc_rte_flow", sizeof(*flow), 0);
2433 [ # # ]: 0 : if (flow == NULL) {
2434 : 0 : rte_flow_error_set(error, ENOMEM,
2435 : : RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
2436 : : "Failed to allocate memory");
2437 : : }
2438 : :
2439 : 0 : return flow;
2440 : : }
2441 : :
2442 : : static void
2443 [ # # # ]: 0 : sfc_flow_free(struct sfc_adapter *sa, struct rte_flow *flow)
2444 : : {
2445 : : const struct sfc_flow_ops_by_spec *ops;
2446 : :
2447 : : ops = sfc_flow_get_ops_by_spec(flow);
2448 [ # # ]: 0 : if (ops != NULL && ops->cleanup != NULL)
2449 : 0 : ops->cleanup(sa, flow);
2450 : :
2451 : 0 : rte_free(flow);
2452 : 0 : }
2453 : :
2454 : : static int
2455 [ # # # ]: 0 : sfc_flow_insert(struct sfc_adapter *sa, struct rte_flow *flow,
2456 : : struct rte_flow_error *error)
2457 : : {
2458 : : const struct sfc_flow_ops_by_spec *ops;
2459 : : int rc;
2460 : :
2461 : : ops = sfc_flow_get_ops_by_spec(flow);
2462 [ # # ]: 0 : if (ops == NULL || ops->insert == NULL) {
2463 : 0 : rte_flow_error_set(error, ENOTSUP,
2464 : : RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
2465 : : "No backend to handle this flow");
2466 : 0 : return rte_errno;
2467 : : }
2468 : :
2469 : 0 : rc = ops->insert(sa, flow);
2470 [ # # ]: 0 : if (rc != 0) {
2471 : 0 : rte_flow_error_set(error, rc, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
2472 : : NULL, "Failed to insert the flow rule");
2473 : : }
2474 : :
2475 : : return rc;
2476 : : }
2477 : :
2478 : : static int
2479 [ # # # ]: 0 : sfc_flow_remove(struct sfc_adapter *sa, struct rte_flow *flow,
2480 : : struct rte_flow_error *error)
2481 : : {
2482 : : const struct sfc_flow_ops_by_spec *ops;
2483 : : int rc;
2484 : :
2485 : : ops = sfc_flow_get_ops_by_spec(flow);
2486 [ # # ]: 0 : if (ops == NULL || ops->remove == NULL) {
2487 : 0 : rte_flow_error_set(error, ENOTSUP,
2488 : : RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
2489 : : "No backend to handle this flow");
2490 : 0 : return rte_errno;
2491 : : }
2492 : :
2493 : 0 : rc = ops->remove(sa, flow);
2494 [ # # ]: 0 : if (rc != 0) {
2495 : 0 : rte_flow_error_set(error, rc, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
2496 : : NULL, "Failed to remove the flow rule");
2497 : : }
2498 : :
2499 : : return rc;
2500 : : }
2501 : :
2502 : : static int
2503 [ # # # ]: 0 : sfc_flow_verify(struct sfc_adapter *sa, struct rte_flow *flow,
2504 : : struct rte_flow_error *error)
2505 : : {
2506 : : const struct sfc_flow_ops_by_spec *ops;
2507 : : int rc = 0;
2508 : :
2509 : : ops = sfc_flow_get_ops_by_spec(flow);
2510 : : if (ops == NULL) {
2511 : 0 : rte_flow_error_set(error, ENOTSUP,
2512 : : RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
2513 : : "No backend to handle this flow");
2514 : 0 : return -rte_errno;
2515 : : }
2516 : :
2517 [ # # ]: 0 : if (ops->verify != NULL) {
2518 : : SFC_ASSERT(sfc_adapter_is_locked(sa));
2519 : 0 : rc = ops->verify(sa, flow);
2520 : : }
2521 : :
2522 [ # # ]: 0 : if (rc != 0) {
2523 : 0 : rte_flow_error_set(error, rc,
2524 : : RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
2525 : : "Failed to verify flow validity with FW");
2526 : 0 : return -rte_errno;
2527 : : }
2528 : :
2529 : : return 0;
2530 : : }
2531 : :
2532 : : static int
2533 : 0 : sfc_flow_validate(struct rte_eth_dev *dev,
2534 : : const struct rte_flow_attr *attr,
2535 : : const struct rte_flow_item pattern[],
2536 : : const struct rte_flow_action actions[],
2537 : : struct rte_flow_error *error)
2538 : : {
2539 : : struct sfc_adapter *sa = sfc_adapter_by_eth_dev(dev);
2540 : : struct rte_flow *flow;
2541 : : int rc;
2542 : :
2543 : 0 : flow = sfc_flow_zmalloc(error);
2544 [ # # ]: 0 : if (flow == NULL)
2545 : 0 : return -rte_errno;
2546 : :
2547 : 0 : sfc_adapter_lock(sa);
2548 : :
2549 : 0 : rc = sfc_flow_parse(dev, attr, pattern, actions, flow, error);
2550 [ # # ]: 0 : if (rc == 0)
2551 : 0 : rc = sfc_flow_verify(sa, flow, error);
2552 : :
2553 : 0 : sfc_flow_free(sa, flow);
2554 : :
2555 : : sfc_adapter_unlock(sa);
2556 : :
2557 : 0 : return rc;
2558 : : }
2559 : :
2560 : : static struct rte_flow *
2561 : 0 : sfc_flow_create(struct rte_eth_dev *dev,
2562 : : const struct rte_flow_attr *attr,
2563 : : const struct rte_flow_item pattern[],
2564 : : const struct rte_flow_action actions[],
2565 : : struct rte_flow_error *error)
2566 : : {
2567 : : struct sfc_adapter *sa = sfc_adapter_by_eth_dev(dev);
2568 : : struct rte_flow *flow;
2569 : :
2570 : 0 : sfc_adapter_lock(sa);
2571 : 0 : flow = sfc_flow_create_locked(sa, false, attr, pattern, actions, error);
2572 : : sfc_adapter_unlock(sa);
2573 : :
2574 : 0 : return flow;
2575 : : }
2576 : :
2577 : : struct rte_flow *
2578 : 0 : sfc_flow_create_locked(struct sfc_adapter *sa, bool internal,
2579 : : const struct rte_flow_attr *attr,
2580 : : const struct rte_flow_item pattern[],
2581 : : const struct rte_flow_action actions[],
2582 : : struct rte_flow_error *error)
2583 : : {
2584 : : struct rte_flow *flow = NULL;
2585 : : int rc;
2586 : :
2587 : : SFC_ASSERT(sfc_adapter_is_locked(sa));
2588 : :
2589 : 0 : flow = sfc_flow_zmalloc(error);
2590 [ # # ]: 0 : if (flow == NULL)
2591 : 0 : goto fail_no_mem;
2592 : :
2593 : 0 : flow->internal = internal;
2594 : :
2595 : 0 : rc = sfc_flow_parse(sa->eth_dev, attr, pattern, actions, flow, error);
2596 [ # # ]: 0 : if (rc != 0)
2597 : 0 : goto fail_bad_value;
2598 : :
2599 : 0 : TAILQ_INSERT_TAIL(&sa->flow_list, flow, entries);
2600 : :
2601 [ # # # # ]: 0 : if (flow->internal || sa->state == SFC_ETHDEV_STARTED) {
2602 : 0 : rc = sfc_flow_insert(sa, flow, error);
2603 [ # # ]: 0 : if (rc != 0)
2604 : 0 : goto fail_flow_insert;
2605 : : }
2606 : :
2607 : : return flow;
2608 : :
2609 : : fail_flow_insert:
2610 [ # # ]: 0 : TAILQ_REMOVE(&sa->flow_list, flow, entries);
2611 : :
2612 : 0 : fail_bad_value:
2613 : 0 : sfc_flow_free(sa, flow);
2614 : :
2615 : : fail_no_mem:
2616 : : return NULL;
2617 : : }
2618 : :
2619 : : static int
2620 : 0 : sfc_flow_destroy(struct rte_eth_dev *dev,
2621 : : struct rte_flow *flow,
2622 : : struct rte_flow_error *error)
2623 : : {
2624 : : struct sfc_adapter *sa = sfc_adapter_by_eth_dev(dev);
2625 : : int rc;
2626 : :
2627 : 0 : sfc_adapter_lock(sa);
2628 : 0 : rc = sfc_flow_destroy_locked(sa, flow, error);
2629 : : sfc_adapter_unlock(sa);
2630 : :
2631 : 0 : return rc;
2632 : : }
2633 : :
2634 : : int
2635 : 0 : sfc_flow_destroy_locked(struct sfc_adapter *sa, struct rte_flow *flow,
2636 : : struct rte_flow_error *error)
2637 : : {
2638 : : struct rte_flow *flow_ptr;
2639 : : int rc = EINVAL;
2640 : :
2641 : : SFC_ASSERT(sfc_adapter_is_locked(sa));
2642 : :
2643 [ # # ]: 0 : TAILQ_FOREACH(flow_ptr, &sa->flow_list, entries) {
2644 [ # # ]: 0 : if (flow_ptr == flow)
2645 : : rc = 0;
2646 : : }
2647 [ # # ]: 0 : if (rc != 0) {
2648 : 0 : rte_flow_error_set(error, rc,
2649 : : RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
2650 : : "Failed to find flow rule to destroy");
2651 : 0 : goto fail_bad_value;
2652 : : }
2653 : :
2654 [ # # # # ]: 0 : if (flow->internal || sa->state == SFC_ETHDEV_STARTED)
2655 : 0 : rc = sfc_flow_remove(sa, flow, error);
2656 : :
2657 [ # # ]: 0 : TAILQ_REMOVE(&sa->flow_list, flow, entries);
2658 : 0 : sfc_flow_free(sa, flow);
2659 : :
2660 : 0 : fail_bad_value:
2661 : 0 : return -rc;
2662 : : }
2663 : :
2664 : : static int
2665 : 0 : sfc_flow_flush(struct rte_eth_dev *dev,
2666 : : struct rte_flow_error *error)
2667 : : {
2668 : : struct sfc_adapter *sa = sfc_adapter_by_eth_dev(dev);
2669 : : struct rte_flow *flow;
2670 : : int ret = 0;
2671 : : void *tmp;
2672 : :
2673 : 0 : sfc_adapter_lock(sa);
2674 : :
2675 [ # # ]: 0 : RTE_TAILQ_FOREACH_SAFE(flow, &sa->flow_list, entries, tmp) {
2676 [ # # ]: 0 : if (flow->internal)
2677 : 0 : continue;
2678 : :
2679 [ # # ]: 0 : if (sa->state == SFC_ETHDEV_STARTED) {
2680 : : int rc;
2681 : :
2682 : 0 : rc = sfc_flow_remove(sa, flow, error);
2683 [ # # ]: 0 : if (rc != 0)
2684 : : ret = rc;
2685 : : }
2686 : :
2687 [ # # ]: 0 : TAILQ_REMOVE(&sa->flow_list, flow, entries);
2688 : 0 : sfc_flow_free(sa, flow);
2689 : : }
2690 : :
2691 : : sfc_adapter_unlock(sa);
2692 : :
2693 : 0 : return -ret;
2694 : : }
2695 : :
2696 : : static int
2697 : 0 : sfc_flow_query(struct rte_eth_dev *dev,
2698 : : struct rte_flow *flow,
2699 : : const struct rte_flow_action *action,
2700 : : void *data,
2701 : : struct rte_flow_error *error)
2702 : : {
2703 : : struct sfc_adapter *sa = sfc_adapter_by_eth_dev(dev);
2704 : : const struct sfc_flow_ops_by_spec *ops;
2705 : : int ret;
2706 : :
2707 : 0 : sfc_adapter_lock(sa);
2708 : :
2709 : : ops = sfc_flow_get_ops_by_spec(flow);
2710 [ # # ]: 0 : if (ops == NULL || ops->query == NULL) {
2711 : 0 : ret = rte_flow_error_set(error, ENOTSUP,
2712 : : RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
2713 : : "No backend to handle this flow");
2714 : 0 : goto fail_no_backend;
2715 : : }
2716 : :
2717 [ # # ]: 0 : if (sa->state != SFC_ETHDEV_STARTED) {
2718 : 0 : ret = rte_flow_error_set(error, EINVAL,
2719 : : RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
2720 : : "Can't query the flow: the adapter is not started");
2721 : 0 : goto fail_not_started;
2722 : : }
2723 : :
2724 : 0 : ret = ops->query(dev, flow, action, data, error);
2725 [ # # ]: 0 : if (ret != 0)
2726 : 0 : goto fail_query;
2727 : :
2728 : : sfc_adapter_unlock(sa);
2729 : :
2730 : 0 : return 0;
2731 : :
2732 : : fail_query:
2733 : 0 : fail_not_started:
2734 : 0 : fail_no_backend:
2735 : : sfc_adapter_unlock(sa);
2736 : 0 : return ret;
2737 : : }
2738 : :
2739 : : static int
2740 : 0 : sfc_flow_isolate(struct rte_eth_dev *dev, int enable,
2741 : : struct rte_flow_error *error)
2742 : : {
2743 : : struct sfc_adapter *sa = sfc_adapter_by_eth_dev(dev);
2744 : : int ret = 0;
2745 : :
2746 : 0 : sfc_adapter_lock(sa);
2747 [ # # ]: 0 : if (sa->state != SFC_ETHDEV_INITIALIZED) {
2748 : 0 : rte_flow_error_set(error, EBUSY,
2749 : : RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
2750 : : NULL, "please close the port first");
2751 : 0 : ret = -rte_errno;
2752 : : } else {
2753 : 0 : sfc_sa2shared(sa)->isolated = (enable) ? B_TRUE : B_FALSE;
2754 : : }
2755 : : sfc_adapter_unlock(sa);
2756 : :
2757 : 0 : return ret;
2758 : : }
2759 : :
2760 : : static int
2761 : 0 : sfc_flow_pick_transfer_proxy(struct rte_eth_dev *dev,
2762 : : uint16_t *transfer_proxy_port,
2763 : : struct rte_flow_error *error)
2764 : : {
2765 : : struct sfc_adapter *sa = sfc_adapter_by_eth_dev(dev);
2766 : : int ret;
2767 : :
2768 : 0 : ret = sfc_mae_get_switch_domain_admin(sa->mae.switch_domain_id,
2769 : : transfer_proxy_port);
2770 [ # # ]: 0 : if (ret != 0) {
2771 : 0 : return rte_flow_error_set(error, ret,
2772 : : RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
2773 : : NULL, NULL);
2774 : : }
2775 : :
2776 : : return 0;
2777 : : }
2778 : :
2779 : : static struct rte_flow_action_handle *
2780 [ # # ]: 0 : sfc_flow_action_handle_create(struct rte_eth_dev *dev,
2781 : : const struct rte_flow_indir_action_conf *conf,
2782 : : const struct rte_flow_action *action,
2783 : : struct rte_flow_error *error)
2784 : : {
2785 : : struct sfc_adapter *sa = sfc_adapter_by_eth_dev(dev);
2786 : : struct rte_flow_action_handle *handle;
2787 : : int ret;
2788 : :
2789 [ # # ]: 0 : if (!conf->transfer) {
2790 : 0 : rte_flow_error_set(error, ENOTSUP,
2791 : : RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
2792 : : "non-transfer domain does not support indirect actions");
2793 : 0 : return NULL;
2794 : : }
2795 : :
2796 [ # # ]: 0 : if (conf->ingress || conf->egress) {
2797 : 0 : rte_flow_error_set(error, EINVAL,
2798 : : RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
2799 : : NULL, "cannot combine ingress/egress with transfer");
2800 : 0 : return NULL;
2801 : : }
2802 : :
2803 : 0 : handle = rte_zmalloc("sfc_rte_flow_action_handle", sizeof(*handle), 0);
2804 [ # # ]: 0 : if (handle == NULL) {
2805 : 0 : rte_flow_error_set(error, ENOMEM,
2806 : : RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
2807 : : "failed to allocate memory");
2808 : 0 : return NULL;
2809 : : }
2810 : :
2811 : 0 : sfc_adapter_lock(sa);
2812 : :
2813 : 0 : ret = sfc_mae_indir_action_create(sa, action, handle, error);
2814 [ # # ]: 0 : if (ret != 0) {
2815 : : sfc_adapter_unlock(sa);
2816 : 0 : rte_free(handle);
2817 : 0 : return NULL;
2818 : : }
2819 : :
2820 : 0 : TAILQ_INSERT_TAIL(&sa->flow_indir_actions, handle, entries);
2821 : :
2822 : 0 : handle->transfer = (bool)conf->transfer;
2823 : :
2824 : : sfc_adapter_unlock(sa);
2825 : :
2826 : 0 : return handle;
2827 : : }
2828 : :
2829 : : static int
2830 : 0 : sfc_flow_action_handle_destroy(struct rte_eth_dev *dev,
2831 : : struct rte_flow_action_handle *handle,
2832 : : struct rte_flow_error *error)
2833 : : {
2834 : : struct sfc_adapter *sa = sfc_adapter_by_eth_dev(dev);
2835 : : struct rte_flow_action_handle *entry;
2836 : : int rc = EINVAL;
2837 : :
2838 : 0 : sfc_adapter_lock(sa);
2839 : :
2840 [ # # ]: 0 : TAILQ_FOREACH(entry, &sa->flow_indir_actions, entries) {
2841 [ # # ]: 0 : if (entry != handle)
2842 : : continue;
2843 : :
2844 [ # # ]: 0 : if (entry->transfer) {
2845 : 0 : rc = sfc_mae_indir_action_destroy(sa, handle,
2846 : : error);
2847 [ # # ]: 0 : if (rc != 0)
2848 : 0 : goto exit;
2849 : : } else {
2850 : : SFC_ASSERT(B_FALSE);
2851 : : }
2852 : :
2853 [ # # ]: 0 : TAILQ_REMOVE(&sa->flow_indir_actions, entry, entries);
2854 : 0 : rte_free(entry);
2855 : 0 : goto exit;
2856 : : }
2857 : :
2858 : 0 : rc = rte_flow_error_set(error, ENOENT,
2859 : : RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
2860 : : "indirect action handle not found");
2861 : :
2862 : 0 : exit:
2863 : : sfc_adapter_unlock(sa);
2864 : 0 : return rc;
2865 : : }
2866 : :
2867 : : static int
2868 : 0 : sfc_flow_action_handle_update(struct rte_eth_dev *dev,
2869 : : struct rte_flow_action_handle *handle,
2870 : : const void *update, struct rte_flow_error *error)
2871 : : {
2872 : : struct sfc_adapter *sa = sfc_adapter_by_eth_dev(dev);
2873 : : struct rte_flow_action_handle *entry;
2874 : : int rc = EINVAL;
2875 : :
2876 : 0 : sfc_adapter_lock(sa);
2877 : :
2878 [ # # ]: 0 : TAILQ_FOREACH(entry, &sa->flow_indir_actions, entries) {
2879 [ # # ]: 0 : if (entry != handle)
2880 : : continue;
2881 : :
2882 [ # # ]: 0 : if (entry->transfer) {
2883 : 0 : rc = sfc_mae_indir_action_update(sa, handle,
2884 : : update, error);
2885 : : } else {
2886 : : SFC_ASSERT(B_FALSE);
2887 : : }
2888 : :
2889 : 0 : goto exit;
2890 : : }
2891 : :
2892 : 0 : rc = rte_flow_error_set(error, ENOENT,
2893 : : RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
2894 : : "indirect action handle not found");
2895 : :
2896 : 0 : exit:
2897 : : sfc_adapter_unlock(sa);
2898 : 0 : return rc;
2899 : : }
2900 : :
2901 : : static int
2902 : 0 : sfc_flow_action_handle_query(struct rte_eth_dev *dev,
2903 : : const struct rte_flow_action_handle *handle,
2904 : : void *data, struct rte_flow_error *error)
2905 : : {
2906 : : struct sfc_adapter *sa = sfc_adapter_by_eth_dev(dev);
2907 : : struct rte_flow_action_handle *entry;
2908 : : int rc = EINVAL;
2909 : :
2910 : 0 : sfc_adapter_lock(sa);
2911 : :
2912 [ # # ]: 0 : TAILQ_FOREACH(entry, &sa->flow_indir_actions, entries) {
2913 [ # # ]: 0 : if (entry != handle)
2914 : : continue;
2915 : :
2916 [ # # ]: 0 : if (entry->transfer) {
2917 : 0 : rc = sfc_mae_indir_action_query(sa, handle,
2918 : : data, error);
2919 : : } else {
2920 : : SFC_ASSERT(B_FALSE);
2921 : : }
2922 : :
2923 : 0 : goto exit;
2924 : : }
2925 : :
2926 : 0 : rc = rte_flow_error_set(error, ENOENT,
2927 : : RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
2928 : : "indirect action handle not found");
2929 : :
2930 : 0 : exit:
2931 : : sfc_adapter_unlock(sa);
2932 : 0 : return rc;
2933 : : }
2934 : :
2935 : : const struct rte_flow_ops sfc_flow_ops = {
2936 : : .validate = sfc_flow_validate,
2937 : : .create = sfc_flow_create,
2938 : : .destroy = sfc_flow_destroy,
2939 : : .flush = sfc_flow_flush,
2940 : : .query = sfc_flow_query,
2941 : : .isolate = sfc_flow_isolate,
2942 : : .action_handle_create = sfc_flow_action_handle_create,
2943 : : .action_handle_destroy = sfc_flow_action_handle_destroy,
2944 : : .action_handle_update = sfc_flow_action_handle_update,
2945 : : .action_handle_query = sfc_flow_action_handle_query,
2946 : : .tunnel_decap_set = sfc_ft_decap_set,
2947 : : .tunnel_match = sfc_ft_match,
2948 : : .tunnel_action_decap_release = sfc_ft_action_decap_release,
2949 : : .tunnel_item_release = sfc_ft_item_release,
2950 : : .get_restore_info = sfc_ft_get_restore_info,
2951 : : .pick_transfer_proxy = sfc_flow_pick_transfer_proxy,
2952 : : };
2953 : :
2954 : : void
2955 : 0 : sfc_flow_init(struct sfc_adapter *sa)
2956 : : {
2957 : : SFC_ASSERT(sfc_adapter_is_locked(sa));
2958 : :
2959 : 0 : TAILQ_INIT(&sa->flow_indir_actions);
2960 : 0 : TAILQ_INIT(&sa->flow_list);
2961 : 0 : }
2962 : :
2963 : : void
2964 : 0 : sfc_flow_fini(struct sfc_adapter *sa)
2965 : : {
2966 : : struct rte_flow *flow;
2967 : : void *tmp;
2968 : :
2969 : : SFC_ASSERT(sfc_adapter_is_locked(sa));
2970 : :
2971 [ # # ]: 0 : RTE_TAILQ_FOREACH_SAFE(flow, &sa->flow_list, entries, tmp) {
2972 [ # # ]: 0 : if (flow->internal)
2973 : 0 : continue;
2974 : :
2975 [ # # ]: 0 : TAILQ_REMOVE(&sa->flow_list, flow, entries);
2976 : 0 : sfc_flow_free(sa, flow);
2977 : : }
2978 : 0 : }
2979 : :
2980 : : void
2981 : 0 : sfc_flow_stop(struct sfc_adapter *sa)
2982 : : {
2983 : : struct rte_flow *flow;
2984 : :
2985 : : SFC_ASSERT(sfc_adapter_is_locked(sa));
2986 : :
2987 [ # # ]: 0 : TAILQ_FOREACH(flow, &sa->flow_list, entries) {
2988 [ # # ]: 0 : if (!flow->internal)
2989 : 0 : sfc_flow_remove(sa, flow, NULL);
2990 : : }
2991 : :
2992 : : /*
2993 : : * MAE counter service is not stopped on flow rule remove to avoid
2994 : : * extra work. Make sure that it is stopped here.
2995 : : */
2996 : 0 : sfc_mae_counter_stop(sa);
2997 : 0 : }
2998 : :
2999 : : int
3000 : 0 : sfc_flow_start(struct sfc_adapter *sa)
3001 : : {
3002 : : struct rte_flow *flow;
3003 : : int rc = 0;
3004 : :
3005 : 0 : sfc_log_init(sa, "entry");
3006 : :
3007 : : SFC_ASSERT(sfc_adapter_is_locked(sa));
3008 : :
3009 : 0 : sfc_ft_counters_reset(sa);
3010 : :
3011 [ # # ]: 0 : TAILQ_FOREACH(flow, &sa->flow_list, entries) {
3012 [ # # ]: 0 : if (flow->internal)
3013 : 0 : continue;
3014 : :
3015 : 0 : rc = sfc_flow_insert(sa, flow, NULL);
3016 [ # # ]: 0 : if (rc != 0)
3017 : 0 : goto fail_bad_flow;
3018 : : }
3019 : :
3020 : 0 : sfc_log_init(sa, "done");
3021 : :
3022 : 0 : fail_bad_flow:
3023 : 0 : return rc;
3024 : : }
3025 : :
3026 : : static void
3027 : 0 : sfc_flow_cleanup(struct sfc_adapter *sa, struct rte_flow *flow)
3028 : : {
3029 [ # # ]: 0 : if (flow == NULL)
3030 : : return;
3031 : :
3032 : 0 : sfc_flow_rss_ctx_del(sa, flow->spec.filter.rss_ctx);
3033 : : }
|