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