Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright 2008-2019 Cisco Systems, Inc. All rights reserved.
3 : : */
4 : :
5 : : #include <errno.h>
6 : : #include <stdint.h>
7 : : #include <rte_log.h>
8 : : #include <ethdev_driver.h>
9 : : #include <rte_flow_driver.h>
10 : : #include <rte_ether.h>
11 : : #include <rte_geneve.h>
12 : : #include <rte_hash.h>
13 : : #include <rte_jhash.h>
14 : : #include <rte_ip.h>
15 : : #include <rte_udp.h>
16 : : #include <rte_memzone.h>
17 : :
18 : : #include "enic_compat.h"
19 : : #include "enic.h"
20 : : #include "vnic_dev.h"
21 : : #include "vnic_nic.h"
22 : :
23 : : #define IP_DEFTTL 64 /* from RFC 1340. */
24 : : #define IP6_VTC_FLOW 0x60000000
25 : :
26 : : /* Up to 1024 TCAM entries */
27 : : #define FM_MAX_TCAM_TABLE_SIZE 1024
28 : :
29 : : /* Up to 4096 entries per exact match table */
30 : : #define FM_MAX_EXACT_TABLE_SIZE 4096
31 : :
32 : : /* Number of counters to increase on for each increment */
33 : : #define FM_COUNTERS_EXPAND 100
34 : :
35 : : #define FM_INVALID_HANDLE 0
36 : :
37 : : /* Low priority used for implicit VF -> representor flow */
38 : : #define FM_LOWEST_PRIORITY 100000
39 : :
40 : : /* High priority used for implicit representor -> VF flow */
41 : : #define FM_HIGHEST_PRIORITY 0
42 : :
43 : : /* Tag used for implicit VF <-> representor flows */
44 : : #define FM_VF_REP_TAG 1
45 : :
46 : : /* Max number of actions supported by VIC is 2K. Make hash table double that. */
47 : : #define FM_MAX_ACTION_TABLE_SIZE 4096
48 : :
49 : : /*
50 : : * Flow exact match tables (FET) in the VIC and rte_flow groups.
51 : : * Use a simple scheme to map groups to tables.
52 : : * Group 0 uses the single TCAM tables, one for each direction.
53 : : * Group 1, 2, ... uses its own exact match table.
54 : : *
55 : : * The TCAM tables are allocated upfront during init.
56 : : *
57 : : * Exact match tables are allocated on demand. 3 paths that lead allocations.
58 : : *
59 : : * 1. Add a flow that jumps from group 0 to group N.
60 : : *
61 : : * If N does not exist, we allocate an exact match table for it, using
62 : : * a dummy key. A key is required for the table.
63 : : *
64 : : * 2. Add a flow that uses group N.
65 : : *
66 : : * If N does not exist, we allocate an exact match table for it, using
67 : : * the flow's key. Subsequent flows to the same group all should have
68 : : * the same key.
69 : : *
70 : : * Without a jump flow to N, N is not reachable in hardware. No packets
71 : : * reach N and match.
72 : : *
73 : : * 3. Add a flow to an empty group N.
74 : : *
75 : : * N has been created via (1) and the dummy key. We free that table, allocate
76 : : * a new table using the new flow's key. Also re-do the existing jump flow to
77 : : * point to the new table.
78 : : */
79 : : #define FM_TCAM_RTE_GROUP 0
80 : :
81 : : struct enic_fm_fet {
82 : : TAILQ_ENTRY(enic_fm_fet) list;
83 : : uint32_t group; /* rte_flow group ID */
84 : : uint64_t handle; /* Exact match table handle from flowman */
85 : : uint8_t ingress;
86 : : uint8_t default_key;
87 : : int ref; /* Reference count via get/put */
88 : : struct fm_key_template key; /* Key associated with the table */
89 : : };
90 : :
91 : : struct enic_fm_counter {
92 : : SLIST_ENTRY(enic_fm_counter) next;
93 : : uint32_t handle;
94 : : };
95 : :
96 : : struct enic_fm_action {
97 : : int ref;
98 : : uint64_t handle;
99 : : struct fm_action key;
100 : : };
101 : :
102 : : /* rte_flow.fm */
103 : : struct enic_fm_flow {
104 : : bool counter_valid;
105 : : uint64_t entry_handle;
106 : : struct enic_fm_action *action;
107 : : struct enic_fm_counter *counter;
108 : : struct enic_fm_fet *fet;
109 : : /* Auto-added steer action for hairpin flows (e.g. vnic->vnic) */
110 : : struct enic_fm_flow *hairpin_steer_flow;
111 : : };
112 : :
113 : : struct enic_fm_jump_flow {
114 : : TAILQ_ENTRY(enic_fm_jump_flow) list;
115 : : struct rte_flow *flow;
116 : : uint32_t group;
117 : : struct fm_tcam_match_entry match;
118 : : struct fm_action action;
119 : : };
120 : :
121 : : /*
122 : : * Flowman uses host memory for commands. This structure is allocated
123 : : * in DMA-able memory.
124 : : */
125 : : union enic_flowman_cmd_mem {
126 : : struct fm_tcam_match_table fm_tcam_match_table;
127 : : struct fm_exact_match_table fm_exact_match_table;
128 : : struct fm_tcam_match_entry fm_tcam_match_entry;
129 : : struct fm_exact_match_entry fm_exact_match_entry;
130 : : struct fm_action fm_action;
131 : : };
132 : :
133 : : /*
134 : : * PF has a flowman instance, and VF representors share it with PF.
135 : : * PF allocates this structure and owns it. VF representors borrow
136 : : * the PF's structure during API calls (e.g. create, query).
137 : : */
138 : : struct enic_flowman {
139 : : struct enic *owner_enic; /* PF */
140 : : struct enic *user_enic; /* API caller (PF or representor) */
141 : : /*
142 : : * Representors and PF share the same underlying flowman.
143 : : * Lock API calls to serialize accesses from them. Only used
144 : : * when VF representors are present.
145 : : */
146 : : rte_spinlock_t lock;
147 : : /* Command buffer */
148 : : struct {
149 : : union enic_flowman_cmd_mem *va;
150 : : dma_addr_t pa;
151 : : } cmd;
152 : : /* TCAM tables allocated upfront, used for group 0 */
153 : : uint64_t ig_tcam_hndl;
154 : : uint64_t eg_tcam_hndl;
155 : : /* Counters */
156 : : SLIST_HEAD(enic_free_counters, enic_fm_counter) counters;
157 : : void *counter_stack;
158 : : uint32_t counters_alloced;
159 : : /* Exact match tables for groups != 0, dynamically allocated */
160 : : TAILQ_HEAD(fet_list, enic_fm_fet) fet_list;
161 : : /*
162 : : * Default exact match tables used for jump actions to
163 : : * non-existent groups.
164 : : */
165 : : struct enic_fm_fet *default_eg_fet;
166 : : struct enic_fm_fet *default_ig_fet;
167 : : /* hash table for Action reuse */
168 : : struct rte_hash *action_hash;
169 : : /* Flows that jump to the default table above */
170 : : TAILQ_HEAD(jump_flow_list, enic_fm_jump_flow) jump_list;
171 : : /*
172 : : * Scratch data used during each invocation of flow_create
173 : : * and flow_validate.
174 : : */
175 : : struct enic_fm_fet *fet;
176 : : struct fm_tcam_match_entry tcam_entry;
177 : : struct fm_action action;
178 : : struct fm_action action_tmp; /* enic_fm_reorder_action_op */
179 : : int action_op_count;
180 : : /* Tags used for representor flows */
181 : : uint8_t vf_rep_tag;
182 : : /* For auto-added steer action for hairpin */
183 : : int need_hairpin_steer;
184 : : uint64_t hairpin_steer_vnic_h;
185 : : };
186 : :
187 : : static int enic_fm_tbl_free(struct enic_flowman *fm, uint64_t handle);
188 : : /*
189 : : * API functions (create, destroy, validate, flush) call begin_fm()
190 : : * upon entering to save the caller enic (PF or VF representor) and
191 : : * lock. Upon exit, they call end_fm() to unlock.
192 : : */
193 : : static struct enic_flowman *begin_fm(struct enic *enic);
194 : : static void end_fm(struct enic_flowman *fm);
195 : : /* Delete internal flows created for representor paths */
196 : : static void delete_rep_flows(struct enic *enic);
197 : :
198 : : /*
199 : : * Common arguments passed to copy_item functions. Use this structure
200 : : * so we can easily add new arguments.
201 : : * item: Item specification.
202 : : * fm_tcam_entry: Flowman TCAM match entry.
203 : : * header_level: 0 for outer header, 1 for inner header.
204 : : */
205 : : struct copy_item_args {
206 : : const struct rte_flow_item *item;
207 : : struct fm_tcam_match_entry *fm_tcam_entry;
208 : : uint8_t header_level;
209 : : struct rte_flow_error *error;
210 : : };
211 : :
212 : : /* functions for copying items into flowman match */
213 : : typedef int (enic_copy_item_fn)(struct copy_item_args *arg);
214 : :
215 : : /* Info about how to copy items into flowman match */
216 : : struct enic_fm_items {
217 : : /* Function for copying and validating an item. */
218 : : enic_copy_item_fn * const copy_item;
219 : : /* List of valid previous items. */
220 : : const enum rte_flow_item_type * const prev_items;
221 : : /*
222 : : * True if it's OK for this item to be the first item. For some NIC
223 : : * versions, it's invalid to start the stack above layer 3.
224 : : */
225 : : const uint8_t valid_start_item;
226 : : };
227 : :
228 : : static enic_copy_item_fn enic_fm_copy_item_eth;
229 : : static enic_copy_item_fn enic_fm_copy_item_ipv4;
230 : : static enic_copy_item_fn enic_fm_copy_item_ipv6;
231 : : static enic_copy_item_fn enic_fm_copy_item_raw;
232 : : static enic_copy_item_fn enic_fm_copy_item_sctp;
233 : : static enic_copy_item_fn enic_fm_copy_item_tcp;
234 : : static enic_copy_item_fn enic_fm_copy_item_udp;
235 : : static enic_copy_item_fn enic_fm_copy_item_vlan;
236 : : static enic_copy_item_fn enic_fm_copy_item_vxlan;
237 : : static enic_copy_item_fn enic_fm_copy_item_gtp;
238 : : static enic_copy_item_fn enic_fm_copy_item_geneve;
239 : : static enic_copy_item_fn enic_fm_copy_item_geneve_opt;
240 : : static enic_copy_item_fn enic_fm_copy_item_ecpri;
241 : :
242 : : /* Ingress actions */
243 : : static const enum rte_flow_action_type enic_fm_supported_ig_actions[] = {
244 : : RTE_FLOW_ACTION_TYPE_COUNT,
245 : : RTE_FLOW_ACTION_TYPE_DROP,
246 : : RTE_FLOW_ACTION_TYPE_FLAG,
247 : : RTE_FLOW_ACTION_TYPE_JUMP,
248 : : RTE_FLOW_ACTION_TYPE_MARK,
249 : : RTE_FLOW_ACTION_TYPE_OF_POP_VLAN,
250 : : RTE_FLOW_ACTION_TYPE_PORT_ID,
251 : : RTE_FLOW_ACTION_TYPE_PASSTHRU,
252 : : RTE_FLOW_ACTION_TYPE_QUEUE,
253 : : RTE_FLOW_ACTION_TYPE_RSS,
254 : : RTE_FLOW_ACTION_TYPE_VOID,
255 : : RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP,
256 : : RTE_FLOW_ACTION_TYPE_VXLAN_DECAP,
257 : : RTE_FLOW_ACTION_TYPE_END, /* END must be the last entry */
258 : : };
259 : :
260 : : /* Egress actions */
261 : : static const enum rte_flow_action_type enic_fm_supported_eg_actions[] = {
262 : : RTE_FLOW_ACTION_TYPE_COUNT,
263 : : RTE_FLOW_ACTION_TYPE_DROP,
264 : : RTE_FLOW_ACTION_TYPE_JUMP,
265 : : RTE_FLOW_ACTION_TYPE_OF_PUSH_VLAN,
266 : : RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_PCP,
267 : : RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID,
268 : : RTE_FLOW_ACTION_TYPE_PORT_ID,
269 : : RTE_FLOW_ACTION_TYPE_PASSTHRU,
270 : : RTE_FLOW_ACTION_TYPE_VOID,
271 : : RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP,
272 : : RTE_FLOW_ACTION_TYPE_END,
273 : : };
274 : :
275 : : static const struct enic_fm_items enic_fm_items[] = {
276 : : [RTE_FLOW_ITEM_TYPE_RAW] = {
277 : : .copy_item = enic_fm_copy_item_raw,
278 : : .valid_start_item = 0,
279 : : .prev_items = (const enum rte_flow_item_type[]) {
280 : : RTE_FLOW_ITEM_TYPE_UDP,
281 : : RTE_FLOW_ITEM_TYPE_END,
282 : : },
283 : : },
284 : : [RTE_FLOW_ITEM_TYPE_ETH] = {
285 : : .copy_item = enic_fm_copy_item_eth,
286 : : .valid_start_item = 1,
287 : : .prev_items = (const enum rte_flow_item_type[]) {
288 : : RTE_FLOW_ITEM_TYPE_END,
289 : : },
290 : : },
291 : : [RTE_FLOW_ITEM_TYPE_VLAN] = {
292 : : .copy_item = enic_fm_copy_item_vlan,
293 : : .valid_start_item = 1,
294 : : .prev_items = (const enum rte_flow_item_type[]) {
295 : : RTE_FLOW_ITEM_TYPE_ETH,
296 : : RTE_FLOW_ITEM_TYPE_END,
297 : : },
298 : : },
299 : : [RTE_FLOW_ITEM_TYPE_IPV4] = {
300 : : .copy_item = enic_fm_copy_item_ipv4,
301 : : .valid_start_item = 1,
302 : : .prev_items = (const enum rte_flow_item_type[]) {
303 : : RTE_FLOW_ITEM_TYPE_ETH,
304 : : RTE_FLOW_ITEM_TYPE_VLAN,
305 : : RTE_FLOW_ITEM_TYPE_END,
306 : : },
307 : : },
308 : : [RTE_FLOW_ITEM_TYPE_IPV6] = {
309 : : .copy_item = enic_fm_copy_item_ipv6,
310 : : .valid_start_item = 1,
311 : : .prev_items = (const enum rte_flow_item_type[]) {
312 : : RTE_FLOW_ITEM_TYPE_ETH,
313 : : RTE_FLOW_ITEM_TYPE_VLAN,
314 : : RTE_FLOW_ITEM_TYPE_END,
315 : : },
316 : : },
317 : : [RTE_FLOW_ITEM_TYPE_UDP] = {
318 : : .copy_item = enic_fm_copy_item_udp,
319 : : .valid_start_item = 1,
320 : : .prev_items = (const enum rte_flow_item_type[]) {
321 : : RTE_FLOW_ITEM_TYPE_IPV4,
322 : : RTE_FLOW_ITEM_TYPE_IPV6,
323 : : RTE_FLOW_ITEM_TYPE_END,
324 : : },
325 : : },
326 : : [RTE_FLOW_ITEM_TYPE_TCP] = {
327 : : .copy_item = enic_fm_copy_item_tcp,
328 : : .valid_start_item = 1,
329 : : .prev_items = (const enum rte_flow_item_type[]) {
330 : : RTE_FLOW_ITEM_TYPE_IPV4,
331 : : RTE_FLOW_ITEM_TYPE_IPV6,
332 : : RTE_FLOW_ITEM_TYPE_END,
333 : : },
334 : : },
335 : : [RTE_FLOW_ITEM_TYPE_SCTP] = {
336 : : .copy_item = enic_fm_copy_item_sctp,
337 : : .valid_start_item = 0,
338 : : .prev_items = (const enum rte_flow_item_type[]) {
339 : : RTE_FLOW_ITEM_TYPE_IPV4,
340 : : RTE_FLOW_ITEM_TYPE_IPV6,
341 : : RTE_FLOW_ITEM_TYPE_END,
342 : : },
343 : : },
344 : : [RTE_FLOW_ITEM_TYPE_VXLAN] = {
345 : : .copy_item = enic_fm_copy_item_vxlan,
346 : : .valid_start_item = 1,
347 : : .prev_items = (const enum rte_flow_item_type[]) {
348 : : RTE_FLOW_ITEM_TYPE_UDP,
349 : : RTE_FLOW_ITEM_TYPE_END,
350 : : },
351 : : },
352 : : [RTE_FLOW_ITEM_TYPE_GTP] = {
353 : : .copy_item = enic_fm_copy_item_gtp,
354 : : .valid_start_item = 0,
355 : : .prev_items = (const enum rte_flow_item_type[]) {
356 : : RTE_FLOW_ITEM_TYPE_UDP,
357 : : RTE_FLOW_ITEM_TYPE_END,
358 : : },
359 : : },
360 : : [RTE_FLOW_ITEM_TYPE_GTPC] = {
361 : : .copy_item = enic_fm_copy_item_gtp,
362 : : .valid_start_item = 1,
363 : : .prev_items = (const enum rte_flow_item_type[]) {
364 : : RTE_FLOW_ITEM_TYPE_UDP,
365 : : RTE_FLOW_ITEM_TYPE_END,
366 : : },
367 : : },
368 : : [RTE_FLOW_ITEM_TYPE_GTPU] = {
369 : : .copy_item = enic_fm_copy_item_gtp,
370 : : .valid_start_item = 1,
371 : : .prev_items = (const enum rte_flow_item_type[]) {
372 : : RTE_FLOW_ITEM_TYPE_UDP,
373 : : RTE_FLOW_ITEM_TYPE_END,
374 : : },
375 : : },
376 : : [RTE_FLOW_ITEM_TYPE_GENEVE] = {
377 : : .copy_item = enic_fm_copy_item_geneve,
378 : : .valid_start_item = 1,
379 : : .prev_items = (const enum rte_flow_item_type[]) {
380 : : RTE_FLOW_ITEM_TYPE_ETH,
381 : : RTE_FLOW_ITEM_TYPE_IPV4,
382 : : RTE_FLOW_ITEM_TYPE_IPV6,
383 : : RTE_FLOW_ITEM_TYPE_UDP,
384 : : RTE_FLOW_ITEM_TYPE_END,
385 : : },
386 : : },
387 : : [RTE_FLOW_ITEM_TYPE_GENEVE_OPT] = {
388 : : .copy_item = enic_fm_copy_item_geneve_opt,
389 : : .valid_start_item = 1,
390 : : /* Can match at most 1 option */
391 : : .prev_items = (const enum rte_flow_item_type[]) {
392 : : RTE_FLOW_ITEM_TYPE_GENEVE,
393 : : RTE_FLOW_ITEM_TYPE_END,
394 : : },
395 : : },
396 : : [RTE_FLOW_ITEM_TYPE_ECPRI] = {
397 : : .copy_item = enic_fm_copy_item_ecpri,
398 : : .valid_start_item = 1,
399 : : .prev_items = (const enum rte_flow_item_type[]) {
400 : : RTE_FLOW_ITEM_TYPE_ETH,
401 : : RTE_FLOW_ITEM_TYPE_UDP,
402 : : RTE_FLOW_ITEM_TYPE_END,
403 : : },
404 : : },
405 : : };
406 : :
407 : : static int
408 : 0 : enic_fm_copy_item_eth(struct copy_item_args *arg)
409 : : {
410 : 0 : const struct rte_flow_item *item = arg->item;
411 : 0 : const struct rte_flow_item_eth *spec = item->spec;
412 : 0 : const struct rte_flow_item_eth *mask = item->mask;
413 : 0 : const uint8_t lvl = arg->header_level;
414 : 0 : struct fm_tcam_match_entry *entry = arg->fm_tcam_entry;
415 : : struct fm_header_set *fm_data, *fm_mask;
416 : :
417 : 0 : ENICPMD_FUNC_TRACE();
418 : : /* Match all if no spec */
419 [ # # ]: 0 : if (!spec)
420 : : return 0;
421 [ # # ]: 0 : if (!mask)
422 : : mask = &rte_flow_item_eth_mask;
423 : 0 : fm_data = &entry->ftm_data.fk_hdrset[lvl];
424 : : fm_mask = &entry->ftm_mask.fk_hdrset[lvl];
425 : 0 : fm_data->fk_header_select |= FKH_ETHER;
426 : 0 : fm_mask->fk_header_select |= FKH_ETHER;
427 : 0 : memcpy(&fm_data->l2.eth, spec, sizeof(struct rte_ether_hdr));
428 : 0 : memcpy(&fm_mask->l2.eth, mask, sizeof(struct rte_ether_hdr));
429 : 0 : return 0;
430 : : }
431 : :
432 : : static int
433 : 0 : enic_fm_copy_item_vlan(struct copy_item_args *arg)
434 : : {
435 : 0 : const struct rte_flow_item *item = arg->item;
436 : 0 : const struct rte_flow_item_vlan *spec = item->spec;
437 : 0 : const struct rte_flow_item_vlan *mask = item->mask;
438 : 0 : const uint8_t lvl = arg->header_level;
439 : 0 : struct fm_tcam_match_entry *entry = arg->fm_tcam_entry;
440 : : struct fm_header_set *fm_data, *fm_mask;
441 : : struct rte_ether_hdr *eth_mask;
442 : : struct rte_ether_hdr *eth_val;
443 : : uint32_t meta;
444 : :
445 : 0 : ENICPMD_FUNC_TRACE();
446 : 0 : fm_data = &entry->ftm_data.fk_hdrset[lvl];
447 : : fm_mask = &entry->ftm_mask.fk_hdrset[lvl];
448 : : /* Outer and inner packet vlans need different flags */
449 : : meta = FKM_VLAN_PRES;
450 [ # # ]: 0 : if (lvl > 0)
451 : : meta = FKM_QTAG;
452 : 0 : fm_data->fk_metadata |= meta;
453 : 0 : fm_mask->fk_metadata |= meta;
454 : :
455 : : /* Match all if no spec */
456 [ # # ]: 0 : if (!spec)
457 : : return 0;
458 [ # # ]: 0 : if (!mask)
459 : : mask = &rte_flow_item_vlan_mask;
460 : :
461 : 0 : eth_mask = (void *)&fm_mask->l2.eth;
462 : 0 : eth_val = (void *)&fm_data->l2.eth;
463 : :
464 : : /*
465 : : * Outer TPID cannot be matched. If protocol is 0, use what is
466 : : * in the eth header.
467 : : */
468 [ # # # # ]: 0 : if (eth_mask->ether_type && mask->hdr.eth_proto)
469 : : return -ENOTSUP;
470 : :
471 : : /*
472 : : * When packet matching, the VIC always compares vlan-stripped
473 : : * L2, regardless of vlan stripping settings. So, the inner type
474 : : * from vlan becomes the ether type of the eth header.
475 : : */
476 [ # # ]: 0 : if (mask->hdr.eth_proto) {
477 : 0 : eth_mask->ether_type = mask->hdr.eth_proto;
478 : 0 : eth_val->ether_type = spec->hdr.eth_proto;
479 : : }
480 : 0 : fm_data->fk_header_select |= FKH_ETHER | FKH_QTAG;
481 : 0 : fm_mask->fk_header_select |= FKH_ETHER | FKH_QTAG;
482 [ # # ]: 0 : fm_data->fk_vlan = rte_be_to_cpu_16(spec->hdr.vlan_tci);
483 [ # # ]: 0 : fm_mask->fk_vlan = rte_be_to_cpu_16(mask->hdr.vlan_tci);
484 : 0 : return 0;
485 : : }
486 : :
487 : : static int
488 : 0 : enic_fm_copy_item_ipv4(struct copy_item_args *arg)
489 : : {
490 : 0 : const struct rte_flow_item *item = arg->item;
491 : 0 : const struct rte_flow_item_ipv4 *spec = item->spec;
492 : 0 : const struct rte_flow_item_ipv4 *mask = item->mask;
493 : 0 : const uint8_t lvl = arg->header_level;
494 : 0 : struct fm_tcam_match_entry *entry = arg->fm_tcam_entry;
495 : : struct fm_header_set *fm_data, *fm_mask;
496 : :
497 : 0 : ENICPMD_FUNC_TRACE();
498 : 0 : fm_data = &entry->ftm_data.fk_hdrset[lvl];
499 : : fm_mask = &entry->ftm_mask.fk_hdrset[lvl];
500 : 0 : fm_data->fk_metadata |= FKM_IPV4;
501 : 0 : fm_mask->fk_metadata |= FKM_IPV4;
502 : :
503 [ # # ]: 0 : if (!spec)
504 : : return 0;
505 [ # # ]: 0 : if (!mask)
506 : : mask = &rte_flow_item_ipv4_mask;
507 : :
508 : 0 : fm_data->fk_header_select |= FKH_IPV4;
509 : 0 : fm_mask->fk_header_select |= FKH_IPV4;
510 : 0 : memcpy(&fm_data->l3.ip4, spec, sizeof(*spec));
511 : 0 : memcpy(&fm_mask->l3.ip4, mask, sizeof(*mask));
512 : 0 : return 0;
513 : : }
514 : :
515 : : static int
516 : 0 : enic_fm_copy_item_ipv6(struct copy_item_args *arg)
517 : : {
518 : 0 : const struct rte_flow_item *item = arg->item;
519 : 0 : const struct rte_flow_item_ipv6 *spec = item->spec;
520 : 0 : const struct rte_flow_item_ipv6 *mask = item->mask;
521 : 0 : const uint8_t lvl = arg->header_level;
522 : 0 : struct fm_tcam_match_entry *entry = arg->fm_tcam_entry;
523 : : struct fm_header_set *fm_data, *fm_mask;
524 : :
525 : 0 : ENICPMD_FUNC_TRACE();
526 : 0 : fm_data = &entry->ftm_data.fk_hdrset[lvl];
527 : : fm_mask = &entry->ftm_mask.fk_hdrset[lvl];
528 : 0 : fm_data->fk_metadata |= FKM_IPV6;
529 : 0 : fm_mask->fk_metadata |= FKM_IPV6;
530 : :
531 [ # # ]: 0 : if (!spec)
532 : : return 0;
533 [ # # ]: 0 : if (!mask)
534 : : mask = &rte_flow_item_ipv6_mask;
535 : :
536 : 0 : fm_data->fk_header_select |= FKH_IPV6;
537 : 0 : fm_mask->fk_header_select |= FKH_IPV6;
538 : 0 : memcpy(&fm_data->l3.ip6, spec, sizeof(struct rte_ipv6_hdr));
539 : 0 : memcpy(&fm_mask->l3.ip6, mask, sizeof(struct rte_ipv6_hdr));
540 : 0 : return 0;
541 : : }
542 : :
543 : : static int
544 : 0 : enic_fm_copy_item_udp(struct copy_item_args *arg)
545 : : {
546 : 0 : const struct rte_flow_item *item = arg->item;
547 : 0 : const struct rte_flow_item_udp *spec = item->spec;
548 : 0 : const struct rte_flow_item_udp *mask = item->mask;
549 : 0 : const uint8_t lvl = arg->header_level;
550 : 0 : struct fm_tcam_match_entry *entry = arg->fm_tcam_entry;
551 : : struct fm_header_set *fm_data, *fm_mask;
552 : :
553 : 0 : ENICPMD_FUNC_TRACE();
554 : 0 : fm_data = &entry->ftm_data.fk_hdrset[lvl];
555 : : fm_mask = &entry->ftm_mask.fk_hdrset[lvl];
556 : 0 : fm_data->fk_metadata |= FKM_UDP;
557 : 0 : fm_mask->fk_metadata |= FKM_UDP;
558 : :
559 [ # # ]: 0 : if (!spec)
560 : : return 0;
561 [ # # ]: 0 : if (!mask)
562 : : mask = &rte_flow_item_udp_mask;
563 : :
564 : 0 : fm_data->fk_header_select |= FKH_UDP;
565 : 0 : fm_mask->fk_header_select |= FKH_UDP;
566 : 0 : memcpy(&fm_data->l4.udp, spec, sizeof(*spec));
567 : 0 : memcpy(&fm_mask->l4.udp, mask, sizeof(*mask));
568 : 0 : return 0;
569 : : }
570 : :
571 : : static int
572 : 0 : enic_fm_copy_item_tcp(struct copy_item_args *arg)
573 : : {
574 : 0 : const struct rte_flow_item *item = arg->item;
575 : 0 : const struct rte_flow_item_tcp *spec = item->spec;
576 : 0 : const struct rte_flow_item_tcp *mask = item->mask;
577 : 0 : const uint8_t lvl = arg->header_level;
578 : 0 : struct fm_tcam_match_entry *entry = arg->fm_tcam_entry;
579 : : struct fm_header_set *fm_data, *fm_mask;
580 : :
581 : 0 : ENICPMD_FUNC_TRACE();
582 : 0 : fm_data = &entry->ftm_data.fk_hdrset[lvl];
583 : : fm_mask = &entry->ftm_mask.fk_hdrset[lvl];
584 : 0 : fm_data->fk_metadata |= FKM_TCP;
585 : 0 : fm_mask->fk_metadata |= FKM_TCP;
586 : :
587 [ # # ]: 0 : if (!spec)
588 : : return 0;
589 [ # # ]: 0 : if (!mask)
590 : : mask = &rte_flow_item_tcp_mask;
591 : :
592 : 0 : fm_data->fk_header_select |= FKH_TCP;
593 : 0 : fm_mask->fk_header_select |= FKH_TCP;
594 : 0 : memcpy(&fm_data->l4.tcp, spec, sizeof(*spec));
595 : 0 : memcpy(&fm_mask->l4.tcp, mask, sizeof(*mask));
596 : 0 : return 0;
597 : : }
598 : :
599 : : static int
600 : 0 : enic_fm_copy_item_sctp(struct copy_item_args *arg)
601 : : {
602 : 0 : const struct rte_flow_item *item = arg->item;
603 : 0 : const struct rte_flow_item_sctp *spec = item->spec;
604 : 0 : const struct rte_flow_item_sctp *mask = item->mask;
605 : 0 : const uint8_t lvl = arg->header_level;
606 : 0 : struct fm_tcam_match_entry *entry = arg->fm_tcam_entry;
607 : : struct fm_header_set *fm_data, *fm_mask;
608 : : uint8_t *ip_proto_mask = NULL;
609 : : uint8_t *ip_proto = NULL;
610 : : uint32_t l3_fkh;
611 : :
612 : 0 : ENICPMD_FUNC_TRACE();
613 : 0 : fm_data = &entry->ftm_data.fk_hdrset[lvl];
614 : : fm_mask = &entry->ftm_mask.fk_hdrset[lvl];
615 : : /*
616 : : * The NIC filter API has no flags for "match sctp", so explicitly
617 : : * set the protocol number in the IP pattern.
618 : : */
619 [ # # ]: 0 : if (fm_data->fk_metadata & FKM_IPV4) {
620 : : struct rte_ipv4_hdr *ip;
621 : 0 : ip = (struct rte_ipv4_hdr *)&fm_mask->l3.ip4;
622 : 0 : ip_proto_mask = &ip->next_proto_id;
623 : 0 : ip = (struct rte_ipv4_hdr *)&fm_data->l3.ip4;
624 : 0 : ip_proto = &ip->next_proto_id;
625 : : l3_fkh = FKH_IPV4;
626 [ # # ]: 0 : } else if (fm_data->fk_metadata & FKM_IPV6) {
627 : : struct rte_ipv6_hdr *ip;
628 : 0 : ip = (struct rte_ipv6_hdr *)&fm_mask->l3.ip6;
629 : 0 : ip_proto_mask = &ip->proto;
630 : 0 : ip = (struct rte_ipv6_hdr *)&fm_data->l3.ip6;
631 : 0 : ip_proto = &ip->proto;
632 : : l3_fkh = FKH_IPV6;
633 : : } else {
634 : : /* Need IPv4/IPv6 pattern first */
635 : : return -EINVAL;
636 : : }
637 : 0 : *ip_proto = IPPROTO_SCTP;
638 : 0 : *ip_proto_mask = 0xff;
639 : 0 : fm_data->fk_header_select |= l3_fkh;
640 : 0 : fm_mask->fk_header_select |= l3_fkh;
641 : :
642 [ # # ]: 0 : if (!spec)
643 : : return 0;
644 [ # # ]: 0 : if (!mask)
645 : : mask = &rte_flow_item_sctp_mask;
646 : :
647 : 0 : fm_data->fk_header_select |= FKH_L4RAW;
648 : 0 : fm_mask->fk_header_select |= FKH_L4RAW;
649 : 0 : memcpy(fm_data->l4.rawdata, spec, sizeof(*spec));
650 : 0 : memcpy(fm_mask->l4.rawdata, mask, sizeof(*mask));
651 : 0 : return 0;
652 : : }
653 : :
654 : : static int
655 : 0 : enic_fm_copy_item_vxlan(struct copy_item_args *arg)
656 : : {
657 : 0 : const struct rte_flow_item *item = arg->item;
658 : 0 : const struct rte_flow_item_vxlan *spec = item->spec;
659 : 0 : const struct rte_flow_item_vxlan *mask = item->mask;
660 : 0 : struct fm_tcam_match_entry *entry = arg->fm_tcam_entry;
661 : : struct fm_header_set *fm_data, *fm_mask;
662 : :
663 : 0 : ENICPMD_FUNC_TRACE();
664 : : /* Only 2 header levels (outer and inner) allowed */
665 [ # # ]: 0 : if (arg->header_level > 0)
666 : : return -EINVAL;
667 : :
668 : : fm_data = &entry->ftm_data.fk_hdrset[0];
669 : : fm_mask = &entry->ftm_mask.fk_hdrset[0];
670 : 0 : fm_data->fk_metadata |= FKM_VXLAN;
671 : 0 : fm_mask->fk_metadata |= FKM_VXLAN;
672 : : /* items from here on out are inner header items */
673 : 0 : arg->header_level = 1;
674 : :
675 : : /* Match all if no spec */
676 [ # # ]: 0 : if (!spec)
677 : : return 0;
678 [ # # ]: 0 : if (!mask)
679 : : mask = &rte_flow_item_vxlan_mask;
680 : :
681 : 0 : fm_data->fk_header_select |= FKH_VXLAN;
682 : 0 : fm_mask->fk_header_select |= FKH_VXLAN;
683 : 0 : memcpy(&fm_data->vxlan, spec, sizeof(*spec));
684 : 0 : memcpy(&fm_mask->vxlan, mask, sizeof(*mask));
685 : 0 : return 0;
686 : : }
687 : :
688 : : static int
689 : 0 : enic_fm_copy_item_gtp(struct copy_item_args *arg)
690 : : {
691 : 0 : const struct rte_flow_item *item = arg->item;
692 : 0 : const struct rte_flow_item_gtp *spec = item->spec;
693 : 0 : const struct rte_flow_item_gtp *mask = item->mask;
694 : 0 : struct fm_tcam_match_entry *entry = arg->fm_tcam_entry;
695 : : struct fm_header_set *fm_data, *fm_mask;
696 : : int off;
697 : : uint16_t udp_gtp_uc_port_be = 0;
698 : :
699 : 0 : ENICPMD_FUNC_TRACE();
700 : : /* Only 2 header levels (outer and inner) allowed */
701 [ # # ]: 0 : if (arg->header_level > 0)
702 : : return -EINVAL;
703 : :
704 : : fm_data = &entry->ftm_data.fk_hdrset[0];
705 : : fm_mask = &entry->ftm_mask.fk_hdrset[0];
706 : :
707 [ # # # # ]: 0 : switch (item->type) {
708 : 0 : case RTE_FLOW_ITEM_TYPE_GTP:
709 : : {
710 : : /* For vanilla GTP, the UDP destination port must be specified
711 : : * but value of the port is not enforced here.
712 : : */
713 [ # # ]: 0 : if (!(fm_data->fk_metadata & FKM_UDP) ||
714 [ # # ]: 0 : !(fm_data->fk_header_select & FKH_UDP) ||
715 [ # # ]: 0 : fm_data->l4.udp.fk_dest == 0)
716 : : return -EINVAL;
717 [ # # ]: 0 : if (!(fm_mask->fk_metadata & FKM_UDP) ||
718 [ # # ]: 0 : !(fm_mask->fk_header_select & FKH_UDP) ||
719 [ # # ]: 0 : fm_mask->l4.udp.fk_dest != 0xFFFF)
720 : : return -EINVAL;
721 : : break;
722 : : }
723 : : case RTE_FLOW_ITEM_TYPE_GTPC:
724 : : {
725 : : udp_gtp_uc_port_be = rte_cpu_to_be_16(RTE_GTPC_UDP_PORT);
726 : : break;
727 : : }
728 : : case RTE_FLOW_ITEM_TYPE_GTPU:
729 : : {
730 : : udp_gtp_uc_port_be = rte_cpu_to_be_16(RTE_GTPU_UDP_PORT);
731 : : break;
732 : : }
733 : : default:
734 : : RTE_ASSERT(0);
735 : : }
736 : :
737 : : /* The GTP-C or GTP-U UDP destination port must be matched. */
738 : : if (udp_gtp_uc_port_be) {
739 [ # # ]: 0 : if (fm_data->fk_metadata & FKM_UDP &&
740 [ # # ]: 0 : fm_data->fk_header_select & FKH_UDP &&
741 [ # # ]: 0 : fm_data->l4.udp.fk_dest != udp_gtp_uc_port_be)
742 : : return -EINVAL;
743 [ # # ]: 0 : if (fm_mask->fk_metadata & FKM_UDP &&
744 [ # # ]: 0 : fm_mask->fk_header_select & FKH_UDP &&
745 [ # # ]: 0 : fm_mask->l4.udp.fk_dest != 0xFFFF)
746 : : return -EINVAL;
747 : :
748 : : /* In any case, add match for GTP-C GTP-U UDP dst port */
749 : 0 : fm_data->fk_metadata |= FKM_UDP;
750 : 0 : fm_data->fk_header_select |= FKH_UDP;
751 : 0 : fm_data->l4.udp.fk_dest = udp_gtp_uc_port_be;
752 : 0 : fm_mask->fk_metadata |= FKM_UDP;
753 : 0 : fm_mask->fk_header_select |= FKH_UDP;
754 : 0 : fm_mask->l4.udp.fk_dest = 0xFFFF;
755 : : }
756 : :
757 : : /* NIC does not support GTP tunnels. No Items are allowed after this.
758 : : * This prevents the specification of further items.
759 : : */
760 : 0 : arg->header_level = 0;
761 : :
762 : : /* Match all if no spec */
763 [ # # ]: 0 : if (!spec)
764 : : return 0;
765 [ # # ]: 0 : if (!mask)
766 : : mask = &rte_flow_item_gtp_mask;
767 : :
768 : : /*
769 : : * Use the raw L4 buffer to match GTP as fm_header_set does not have
770 : : * GTP header. UDP dst port must be specific. Using the raw buffer
771 : : * does not affect such UDP item, since we skip UDP in the raw buffer.
772 : : */
773 : 0 : fm_data->fk_header_select |= FKH_L4RAW;
774 : 0 : fm_mask->fk_header_select |= FKH_L4RAW;
775 : : off = sizeof(fm_data->l4.udp);
776 : 0 : memcpy(&fm_data->l4.rawdata[off], spec, sizeof(*spec));
777 : 0 : memcpy(&fm_mask->l4.rawdata[off], mask, sizeof(*mask));
778 : 0 : return 0;
779 : : }
780 : :
781 : : static int
782 : 0 : enic_fm_copy_item_geneve(struct copy_item_args *arg)
783 : : {
784 : 0 : const struct rte_flow_item *item = arg->item;
785 : 0 : const struct rte_flow_item_geneve *spec = item->spec;
786 : 0 : const struct rte_flow_item_geneve *mask = item->mask;
787 : 0 : struct fm_tcam_match_entry *entry = arg->fm_tcam_entry;
788 : : struct fm_header_set *fm_data, *fm_mask;
789 : : int off;
790 : :
791 : 0 : ENICPMD_FUNC_TRACE();
792 : : /* Only 2 header levels (outer and inner) allowed */
793 [ # # ]: 0 : if (arg->header_level > 0)
794 : : return -EINVAL;
795 : :
796 : : fm_data = &entry->ftm_data.fk_hdrset[0];
797 : : fm_mask = &entry->ftm_mask.fk_hdrset[0];
798 : 0 : fm_data->fk_metadata |= FKM_GENEVE;
799 : 0 : fm_mask->fk_metadata |= FKM_GENEVE;
800 : : /* items from here on out are inner header items, except options */
801 : 0 : arg->header_level = 1;
802 : :
803 : : /* Match all if no spec */
804 [ # # ]: 0 : if (!spec)
805 : : return 0;
806 [ # # ]: 0 : if (!mask)
807 : : mask = &rte_flow_item_geneve_mask;
808 : :
809 : : /*
810 : : * Use the raw L4 buffer to match geneve as fm_header_set does
811 : : * not have geneve header. A UDP item may precede the geneve
812 : : * item. Using the raw buffer does not affect such UDP item,
813 : : * since we skip UDP in the raw buffer.
814 : : */
815 : 0 : fm_data->fk_header_select |= FKH_L4RAW;
816 : 0 : fm_mask->fk_header_select |= FKH_L4RAW;
817 : : off = sizeof(fm_data->l4.udp);
818 : 0 : memcpy(&fm_data->l4.rawdata[off], spec, sizeof(struct rte_geneve_hdr));
819 : 0 : memcpy(&fm_mask->l4.rawdata[off], mask, sizeof(struct rte_geneve_hdr));
820 : 0 : return 0;
821 : : }
822 : :
823 : : static int
824 : 0 : enic_fm_copy_item_geneve_opt(struct copy_item_args *arg)
825 : : {
826 : 0 : const struct rte_flow_item *item = arg->item;
827 : 0 : const struct rte_flow_item_geneve_opt *spec = item->spec;
828 : 0 : const struct rte_flow_item_geneve_opt *mask = item->mask;
829 : 0 : struct fm_tcam_match_entry *entry = arg->fm_tcam_entry;
830 : : struct fm_header_set *fm_data, *fm_mask;
831 : : struct rte_geneve_hdr *geneve;
832 : : int off, len;
833 : :
834 : 0 : ENICPMD_FUNC_TRACE();
835 : : fm_data = &entry->ftm_data.fk_hdrset[0];
836 : : fm_mask = &entry->ftm_mask.fk_hdrset[0];
837 : : /* Match all if no spec */
838 [ # # ]: 0 : if (!spec)
839 : : return 0;
840 [ # # ]: 0 : if (!mask)
841 : : mask = &rte_flow_item_geneve_opt_mask;
842 : :
843 [ # # ]: 0 : if (spec->option_len > 0 &&
844 [ # # # # ]: 0 : (spec->data == NULL || mask->data == NULL)) {
845 : 0 : return rte_flow_error_set(arg->error, EINVAL,
846 : : RTE_FLOW_ERROR_TYPE_ITEM,
847 : : NULL, "enic: geneve_opt unexpected null data");
848 : : }
849 : : /*
850 : : * Geneve item must already be in the raw buffer. Append the
851 : : * option pattern to it. There are two limitations.
852 : : * (1) Can match only the 1st option, the first one following Geneve
853 : : * (2) Geneve header must specify option length, as HW does not
854 : : * have "has Geneve option" flag.
855 : : */
856 : : RTE_ASSERT((fm_data->fk_header_select & FKH_L4RAW) != 0);
857 : : RTE_ASSERT((fm_mask->fk_header_select & FKH_L4RAW) != 0);
858 : : off = sizeof(fm_data->l4.udp);
859 : : geneve = (struct rte_geneve_hdr *)&fm_data->l4.rawdata[off];
860 [ # # ]: 0 : if (geneve->opt_len == 0) {
861 : 0 : return rte_flow_error_set(arg->error, EINVAL,
862 : : RTE_FLOW_ERROR_TYPE_ITEM,
863 : : NULL, "enic: geneve_opt requires non-zero geneve option length");
864 : : }
865 : : geneve = (struct rte_geneve_hdr *)&fm_mask->l4.rawdata[off];
866 [ # # ]: 0 : if (geneve->opt_len == 0) {
867 : 0 : return rte_flow_error_set(arg->error, EINVAL,
868 : : RTE_FLOW_ERROR_TYPE_ITEM,
869 : : NULL, "enic: geneve_opt requires non-zero geneve option length mask");
870 : : }
871 : : off = sizeof(fm_data->l4.udp) + sizeof(struct rte_geneve_hdr);
872 [ # # ]: 0 : if (off + (spec->option_len + 1) * 4 > FM_LAYER_SIZE) {
873 : 0 : return rte_flow_error_set(arg->error, EINVAL,
874 : : RTE_FLOW_ERROR_TYPE_ITEM,
875 : : NULL, "enic: geneve_opt too large");
876 : : }
877 : : /* Copy option header */
878 [ # # ]: 0 : memcpy(&fm_data->l4.rawdata[off], spec, 4);
879 : 0 : memcpy(&fm_mask->l4.rawdata[off], mask, 4);
880 : : /* Copy option data */
881 [ # # ]: 0 : if (spec->option_len > 0) {
882 : : off += 4;
883 : 0 : len = spec->option_len * 4;
884 : 0 : memcpy(&fm_data->l4.rawdata[off], spec->data, len);
885 : 0 : memcpy(&fm_mask->l4.rawdata[off], mask->data, len);
886 : : }
887 : : return 0;
888 : : }
889 : :
890 : : /* Match eCPRI combined message header */
891 : : static int
892 : 0 : enic_fm_copy_item_ecpri(struct copy_item_args *arg)
893 : : {
894 : 0 : const struct rte_flow_item *item = arg->item;
895 : 0 : const struct rte_flow_item_ecpri *spec = item->spec;
896 : 0 : const struct rte_flow_item_ecpri *mask = item->mask;
897 : 0 : struct fm_tcam_match_entry *entry = arg->fm_tcam_entry;
898 : : struct fm_header_set *fm_data, *fm_mask;
899 : : uint8_t *fm_data_to, *fm_mask_to;
900 : :
901 : 0 : ENICPMD_FUNC_TRACE();
902 : :
903 : : /* Tunneling not supported- only matching on inner eCPRI fields. */
904 [ # # ]: 0 : if (arg->header_level > 0)
905 : : return -EINVAL;
906 : :
907 : : /* Need both spec and mask */
908 [ # # ]: 0 : if (!spec || !mask)
909 : : return -EINVAL;
910 : :
911 : : fm_data = &entry->ftm_data.fk_hdrset[0];
912 : : fm_mask = &entry->ftm_mask.fk_hdrset[0];
913 : :
914 : : /* eCPRI can only follow L2/VLAN layer if ethernet type is 0xAEFE. */
915 [ # # ]: 0 : if (!(fm_data->fk_metadata & FKM_UDP) &&
916 [ # # # # ]: 0 : (fm_mask->l2.eth.fk_ethtype != UINT16_MAX ||
917 [ # # # # ]: 0 : rte_cpu_to_be_16(fm_data->l2.eth.fk_ethtype) !=
918 : : RTE_ETHER_TYPE_ECPRI))
919 : : return -EINVAL;
920 : :
921 [ # # ]: 0 : if (fm_data->fk_metadata & FKM_UDP) {
922 : : /* eCPRI on UDP */
923 : 0 : fm_data->fk_header_select |= FKH_L4RAW;
924 : 0 : fm_mask->fk_header_select |= FKH_L4RAW;
925 : 0 : fm_data_to = &fm_data->l4.rawdata[sizeof(fm_data->l4.udp)];
926 : 0 : fm_mask_to = &fm_mask->l4.rawdata[sizeof(fm_data->l4.udp)];
927 : : } else {
928 : : /* eCPRI directly after Etherent header */
929 : 0 : fm_data->fk_header_select |= FKH_L3RAW;
930 : 0 : fm_mask->fk_header_select |= FKH_L3RAW;
931 : 0 : fm_data_to = &fm_data->l3.rawdata[0];
932 : 0 : fm_mask_to = &fm_mask->l3.rawdata[0];
933 : : }
934 : :
935 : : /*
936 : : * Use the raw L3 or L4 buffer to match eCPRI since fm_header_set does
937 : : * not have eCPRI header. Only 1st message header of PDU can be matched.
938 : : * "C" * bit ignored.
939 : : */
940 : : memcpy(fm_data_to, spec, sizeof(*spec));
941 : : memcpy(fm_mask_to, mask, sizeof(*mask));
942 : 0 : return 0;
943 : : }
944 : :
945 : : /*
946 : : * Currently, raw pattern match is very limited. It is intended for matching
947 : : * UDP tunnel header (e.g. vxlan or geneve).
948 : : */
949 : : static int
950 : 0 : enic_fm_copy_item_raw(struct copy_item_args *arg)
951 : : {
952 : 0 : const struct rte_flow_item *item = arg->item;
953 : 0 : const struct rte_flow_item_raw *spec = item->spec;
954 : 0 : const struct rte_flow_item_raw *mask = item->mask;
955 : 0 : const uint8_t lvl = arg->header_level;
956 : 0 : struct fm_tcam_match_entry *entry = arg->fm_tcam_entry;
957 : : struct fm_header_set *fm_data, *fm_mask;
958 : :
959 : 0 : ENICPMD_FUNC_TRACE();
960 : : /* Cannot be used for inner packet */
961 [ # # ]: 0 : if (lvl > 0)
962 : : return -EINVAL;
963 : : /* Need both spec and mask */
964 [ # # ]: 0 : if (!spec || !mask)
965 : : return -EINVAL;
966 : : /* Only supports relative with offset 0 */
967 [ # # ]: 0 : if (!spec->relative || spec->offset != 0 || spec->search ||
968 [ # # ]: 0 : spec->limit)
969 : : return -EINVAL;
970 : : /* Need non-null pattern that fits within the NIC's filter pattern */
971 [ # # ]: 0 : if (spec->length == 0 ||
972 [ # # ]: 0 : spec->length + sizeof(struct rte_udp_hdr) > FM_LAYER_SIZE ||
973 [ # # # # ]: 0 : !spec->pattern || !mask->pattern)
974 : : return -EINVAL;
975 : : /*
976 : : * Mask fields, including length, are often set to zero. Assume that
977 : : * means "same as spec" to avoid breaking existing apps. If length
978 : : * is not zero, then it should be >= spec length.
979 : : *
980 : : * No more pattern follows this, so append to the L4 layer instead of
981 : : * L5 to work with both recent and older VICs.
982 : : */
983 [ # # # # ]: 0 : if (mask->length != 0 && mask->length < spec->length)
984 : : return -EINVAL;
985 : :
986 : : fm_data = &entry->ftm_data.fk_hdrset[lvl];
987 : : fm_mask = &entry->ftm_mask.fk_hdrset[lvl];
988 : 0 : fm_data->fk_header_select |= FKH_L4RAW;
989 : 0 : fm_mask->fk_header_select |= FKH_L4RAW;
990 : 0 : fm_data->fk_header_select &= ~FKH_UDP;
991 : 0 : fm_mask->fk_header_select &= ~FKH_UDP;
992 : 0 : memcpy(fm_data->l4.rawdata + sizeof(struct rte_udp_hdr),
993 : : spec->pattern, spec->length);
994 : 0 : memcpy(fm_mask->l4.rawdata + sizeof(struct rte_udp_hdr),
995 : 0 : mask->pattern, spec->length);
996 : 0 : return 0;
997 : : }
998 : :
999 : : static int
1000 : : flowman_cmd(struct enic_flowman *fm, uint64_t *args, int nargs)
1001 : : {
1002 : 0 : return vnic_dev_flowman_cmd(fm->owner_enic->vdev, args, nargs);
1003 : : }
1004 : :
1005 : : static int
1006 : 0 : enic_fet_alloc(struct enic_flowman *fm, uint8_t ingress,
1007 : : struct fm_key_template *key, int entries,
1008 : : struct enic_fm_fet **fet_out)
1009 : : {
1010 : : struct fm_exact_match_table *cmd;
1011 : : struct fm_header_set *hdr;
1012 : : struct enic_fm_fet *fet;
1013 : : uint64_t args[3];
1014 : : int ret;
1015 : :
1016 : 0 : ENICPMD_FUNC_TRACE();
1017 : 0 : fet = calloc(1, sizeof(struct enic_fm_fet));
1018 [ # # ]: 0 : if (fet == NULL)
1019 : : return -ENOMEM;
1020 [ # # ]: 0 : cmd = &fm->cmd.va->fm_exact_match_table;
1021 : : memset(cmd, 0, sizeof(*cmd));
1022 : 0 : cmd->fet_direction = ingress ? FM_INGRESS : FM_EGRESS;
1023 : 0 : cmd->fet_stage = FM_STAGE_LAST;
1024 [ # # ]: 0 : cmd->fet_max_entries = entries ? entries : FM_MAX_EXACT_TABLE_SIZE;
1025 [ # # ]: 0 : if (key == NULL) {
1026 : 0 : hdr = &cmd->fet_key.fk_hdrset[0];
1027 : : memset(hdr, 0, sizeof(*hdr));
1028 : 0 : hdr->fk_header_select = FKH_IPV4 | FKH_UDP;
1029 : 0 : hdr->l3.ip4.fk_saddr = 0xFFFFFFFF;
1030 : 0 : hdr->l3.ip4.fk_daddr = 0xFFFFFFFF;
1031 : 0 : hdr->l4.udp.fk_source = 0xFFFF;
1032 : 0 : hdr->l4.udp.fk_dest = 0xFFFF;
1033 : 0 : fet->default_key = 1;
1034 : : } else {
1035 : 0 : memcpy(&cmd->fet_key, key, sizeof(*key));
1036 : 0 : memcpy(&fet->key, key, sizeof(*key));
1037 : 0 : fet->default_key = 0;
1038 : : }
1039 : 0 : cmd->fet_key.fk_packet_tag = 1;
1040 : :
1041 : 0 : args[0] = FM_EXACT_TABLE_ALLOC;
1042 : 0 : args[1] = fm->cmd.pa;
1043 : : ret = flowman_cmd(fm, args, 2);
1044 [ # # ]: 0 : if (ret) {
1045 : 0 : ENICPMD_LOG(ERR, "cannot alloc exact match table: rc=%d", ret);
1046 : 0 : free(fet);
1047 : 0 : return ret;
1048 : : }
1049 : 0 : fet->handle = args[0];
1050 : 0 : fet->ingress = ingress;
1051 : 0 : ENICPMD_LOG(DEBUG, "allocated exact match table: handle=0x%" PRIx64,
1052 : : fet->handle);
1053 : 0 : *fet_out = fet;
1054 : 0 : return 0;
1055 : : }
1056 : :
1057 : : static void
1058 : 0 : enic_fet_free(struct enic_flowman *fm, struct enic_fm_fet *fet)
1059 : : {
1060 : 0 : ENICPMD_FUNC_TRACE();
1061 : 0 : enic_fm_tbl_free(fm, fet->handle);
1062 [ # # ]: 0 : if (!fet->default_key)
1063 [ # # ]: 0 : TAILQ_REMOVE(&fm->fet_list, fet, list);
1064 : 0 : free(fet);
1065 : 0 : }
1066 : :
1067 : : /*
1068 : : * Get the exact match table for the given combination of
1069 : : * <group, ingress, key>. Allocate one on the fly as necessary.
1070 : : */
1071 : : static int
1072 : 0 : enic_fet_get(struct enic_flowman *fm,
1073 : : uint32_t group,
1074 : : uint8_t ingress,
1075 : : struct fm_key_template *key,
1076 : : struct enic_fm_fet **fet_out,
1077 : : struct rte_flow_error *error)
1078 : : {
1079 : : struct enic_fm_fet *fet;
1080 : :
1081 : 0 : ENICPMD_FUNC_TRACE();
1082 : : /* See if we already have this table open */
1083 [ # # ]: 0 : TAILQ_FOREACH(fet, &fm->fet_list, list) {
1084 [ # # # # ]: 0 : if (fet->group == group && fet->ingress == ingress)
1085 : : break;
1086 : : }
1087 [ # # ]: 0 : if (fet == NULL) {
1088 : : /* Jumping to a non-existing group? Use the default table */
1089 [ # # ]: 0 : if (key == NULL) {
1090 [ # # ]: 0 : fet = ingress ? fm->default_ig_fet : fm->default_eg_fet;
1091 [ # # ]: 0 : } else if (enic_fet_alloc(fm, ingress, key, 0, &fet)) {
1092 : 0 : return rte_flow_error_set(error, EINVAL,
1093 : : RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1094 : : NULL, "enic: cannot get exact match table");
1095 : : }
1096 : 0 : fet->group = group;
1097 : : /* Default table is never on the open table list */
1098 [ # # ]: 0 : if (!fet->default_key)
1099 [ # # ]: 0 : TAILQ_INSERT_HEAD(&fm->fet_list, fet, list);
1100 : : }
1101 : 0 : fet->ref++;
1102 : 0 : *fet_out = fet;
1103 [ # # # # ]: 0 : ENICPMD_LOG(DEBUG, "fet_get: %s %s group=%u ref=%u",
1104 : : fet->default_key ? "default" : "",
1105 : : fet->ingress ? "ingress" : "egress",
1106 : : fet->group, fet->ref);
1107 : 0 : return 0;
1108 : : }
1109 : :
1110 : : static void
1111 : 0 : enic_fet_put(struct enic_flowman *fm, struct enic_fm_fet *fet)
1112 : : {
1113 : 0 : ENICPMD_FUNC_TRACE();
1114 : : RTE_ASSERT(fet->ref > 0);
1115 : 0 : fet->ref--;
1116 [ # # # # ]: 0 : ENICPMD_LOG(DEBUG, "fet_put: %s %s group=%u ref=%u",
1117 : : fet->default_key ? "default" : "",
1118 : : fet->ingress ? "ingress" : "egress",
1119 : : fet->group, fet->ref);
1120 [ # # ]: 0 : if (fet->ref == 0)
1121 : 0 : enic_fet_free(fm, fet);
1122 : 0 : }
1123 : :
1124 : : /* Return 1 if current item is valid on top of the previous one. */
1125 : : static int
1126 : 0 : fm_item_stacking_valid(enum rte_flow_item_type prev_item,
1127 : : const struct enic_fm_items *item_info,
1128 : : uint8_t is_first_item)
1129 : : {
1130 : 0 : enum rte_flow_item_type const *allowed_items = item_info->prev_items;
1131 : :
1132 : 0 : ENICPMD_FUNC_TRACE();
1133 [ # # ]: 0 : for (; *allowed_items != RTE_FLOW_ITEM_TYPE_END; allowed_items++) {
1134 [ # # ]: 0 : if (prev_item == *allowed_items)
1135 : : return 1;
1136 : : }
1137 : :
1138 : : /* This is the first item in the stack. Check if that's cool */
1139 [ # # # # ]: 0 : if (is_first_item && item_info->valid_start_item)
1140 : 0 : return 1;
1141 : : return 0;
1142 : : }
1143 : :
1144 : : /*
1145 : : * Build the flow manager match entry structure from the provided pattern.
1146 : : * The pattern is validated as the items are copied.
1147 : : */
1148 : : static int
1149 : 0 : enic_fm_copy_entry(struct enic_flowman *fm,
1150 : : const struct rte_flow_item pattern[],
1151 : : struct rte_flow_error *error)
1152 : : {
1153 : : const struct enic_fm_items *item_info;
1154 : : enum rte_flow_item_type prev_item;
1155 : : const struct rte_flow_item *item;
1156 : : struct copy_item_args args;
1157 : : uint8_t prev_header_level;
1158 : : uint8_t is_first_item;
1159 : : int ret;
1160 : :
1161 : 0 : ENICPMD_FUNC_TRACE();
1162 : : item = pattern;
1163 : : is_first_item = 1;
1164 : : prev_item = RTE_FLOW_ITEM_TYPE_END;
1165 : :
1166 : 0 : args.fm_tcam_entry = &fm->tcam_entry;
1167 : 0 : args.header_level = 0;
1168 : : prev_header_level = 0;
1169 [ # # ]: 0 : for (; item->type != RTE_FLOW_ITEM_TYPE_END; item++) {
1170 : : /*
1171 : : * Get info about how to validate and copy the item. If NULL
1172 : : * is returned the nic does not support the item.
1173 : : */
1174 [ # # ]: 0 : if (item->type == RTE_FLOW_ITEM_TYPE_VOID)
1175 : 0 : continue;
1176 : :
1177 : 0 : item_info = &enic_fm_items[item->type];
1178 : :
1179 [ # # ]: 0 : if (item->type >= RTE_DIM(enic_fm_items) ||
1180 [ # # ]: 0 : item_info->copy_item == NULL) {
1181 : 0 : return rte_flow_error_set(error, ENOTSUP,
1182 : : RTE_FLOW_ERROR_TYPE_ITEM,
1183 : : NULL, "enic: unsupported item");
1184 : : }
1185 : : /*
1186 : : * Check vNIC feature dependencies. Geneve item needs
1187 : : * Geneve offload feature
1188 : : */
1189 [ # # ]: 0 : if (item->type == RTE_FLOW_ITEM_TYPE_GENEVE &&
1190 [ # # ]: 0 : !fm->user_enic->geneve) {
1191 : 0 : return rte_flow_error_set(error, ENOTSUP,
1192 : : RTE_FLOW_ERROR_TYPE_ITEM,
1193 : : NULL, "enic: geneve not supported");
1194 : : }
1195 : : /* check to see if item stacking is valid */
1196 [ # # ]: 0 : if (!fm_item_stacking_valid(prev_item, item_info,
1197 : : is_first_item))
1198 : 0 : goto stacking_error;
1199 : :
1200 : 0 : args.item = item;
1201 : 0 : args.error = error;
1202 [ # # ]: 0 : if (error)
1203 : 0 : error->type = RTE_FLOW_ERROR_TYPE_NONE;
1204 : 0 : ret = item_info->copy_item(&args);
1205 [ # # ]: 0 : if (ret) {
1206 : : /* If copy_item set the error, return that */
1207 [ # # # # ]: 0 : if (error && error->type != RTE_FLOW_ERROR_TYPE_NONE)
1208 : : return ret;
1209 : 0 : goto item_not_supported;
1210 : : }
1211 : : /* Going from outer to inner? Treat it as a new packet start */
1212 [ # # ]: 0 : if (prev_header_level != args.header_level) {
1213 : : prev_item = RTE_FLOW_ITEM_TYPE_END;
1214 : : is_first_item = 1;
1215 : : } else {
1216 : 0 : prev_item = item->type;
1217 : : is_first_item = 0;
1218 : : }
1219 : : prev_header_level = args.header_level;
1220 : : }
1221 : : return 0;
1222 : :
1223 : : item_not_supported:
1224 : 0 : return rte_flow_error_set(error, -ret, RTE_FLOW_ERROR_TYPE_ITEM,
1225 : : NULL, "enic: unsupported item type");
1226 : :
1227 : : stacking_error:
1228 : 0 : return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM,
1229 : : item, "enic: unsupported item stack");
1230 : : }
1231 : :
1232 : : static void
1233 : : flow_item_skip_void(const struct rte_flow_item **item)
1234 : : {
1235 : 0 : for ( ; ; (*item)++)
1236 [ # # # # : 0 : if ((*item)->type != RTE_FLOW_ITEM_TYPE_VOID)
# # # # #
# ]
1237 : : return;
1238 : : }
1239 : :
1240 : : static void
1241 : : append_template(void **template, uint8_t *off, const void *data, int len)
1242 : : {
1243 : : memcpy(*template, data, len);
1244 : 0 : *template = (char *)*template + len;
1245 : 0 : *off = *off + len;
1246 : : }
1247 : :
1248 : : static int
1249 : 0 : enic_fm_append_action_op(struct enic_flowman *fm,
1250 : : struct fm_action_op *fm_op,
1251 : : struct rte_flow_error *error)
1252 : : {
1253 : : int count;
1254 : :
1255 : 0 : count = fm->action_op_count;
1256 : 0 : ENICPMD_LOG(DEBUG, "append action op: idx=%d op=%u",
1257 : : count, fm_op->fa_op);
1258 [ # # ]: 0 : if (count == FM_ACTION_OP_MAX) {
1259 : 0 : return rte_flow_error_set(error, EINVAL,
1260 : : RTE_FLOW_ERROR_TYPE_ACTION, NULL,
1261 : : "too many action operations");
1262 : : }
1263 : 0 : fm->action.fma_action_ops[count] = *fm_op;
1264 : 0 : fm->action_op_count = count + 1;
1265 : 0 : return 0;
1266 : : }
1267 : :
1268 : : static struct fm_action_op *
1269 : : find_prev_action_op(struct enic_flowman *fm, uint32_t opcode)
1270 : : {
1271 : : struct fm_action_op *op;
1272 : : int i;
1273 : :
1274 [ # # ]: 0 : for (i = 0; i < fm->action_op_count; i++) {
1275 : 0 : op = &fm->action.fma_action_ops[i];
1276 [ # # ]: 0 : if (op->fa_op == opcode)
1277 : : return op;
1278 : : }
1279 : : return NULL;
1280 : : }
1281 : :
1282 : : /* NIC requires that 1st steer appear before decap.
1283 : : * Correct example: steer, decap, steer, steer, ...
1284 : : */
1285 : : static void
1286 : 0 : enic_fm_reorder_action_op(struct enic_flowman *fm)
1287 : : {
1288 : : struct fm_action_op *op, *steer, *decap;
1289 : : struct fm_action_op tmp_op;
1290 : :
1291 : 0 : ENICPMD_FUNC_TRACE();
1292 : : /* Find 1st steer and decap */
1293 : 0 : op = fm->action.fma_action_ops;
1294 : : steer = NULL;
1295 : : decap = NULL;
1296 [ # # ]: 0 : while (op->fa_op != FMOP_END) {
1297 [ # # # # ]: 0 : if (!decap && (op->fa_op == FMOP_DECAP_NOSTRIP ||
1298 : : op->fa_op == FMOP_DECAP_STRIP))
1299 : : decap = op;
1300 [ # # # # ]: 0 : else if (!steer && op->fa_op == FMOP_RQ_STEER)
1301 : : steer = op;
1302 : 0 : op++;
1303 : : }
1304 : : /* If decap is before steer, swap */
1305 [ # # # # ]: 0 : if (steer && decap && decap < steer) {
1306 : : op = fm->action.fma_action_ops;
1307 : 0 : ENICPMD_LOG(DEBUG, "swap decap %ld <-> steer %ld",
1308 : : (long)(decap - op), (long)(steer - op));
1309 : 0 : tmp_op = *decap;
1310 : 0 : *decap = *steer;
1311 : 0 : *steer = tmp_op;
1312 : : }
1313 : 0 : }
1314 : :
1315 : : /* VXLAN decap is done via flowman compound action */
1316 : : static int
1317 : 0 : enic_fm_copy_vxlan_decap(struct enic_flowman *fm,
1318 : : struct fm_tcam_match_entry *fmt,
1319 : : const struct rte_flow_action *action,
1320 : : struct rte_flow_error *error)
1321 : : {
1322 : : struct fm_header_set *fm_data;
1323 : : struct fm_action_op fm_op;
1324 : :
1325 : 0 : ENICPMD_FUNC_TRACE();
1326 : : fm_data = &fmt->ftm_data.fk_hdrset[0];
1327 [ # # ]: 0 : if (!(fm_data->fk_metadata & FKM_VXLAN)) {
1328 : 0 : return rte_flow_error_set(error, EINVAL,
1329 : : RTE_FLOW_ERROR_TYPE_ACTION, action,
1330 : : "vxlan-decap: vxlan must be in pattern");
1331 : : }
1332 : :
1333 : : memset(&fm_op, 0, sizeof(fm_op));
1334 : 0 : fm_op.fa_op = FMOP_DECAP_NOSTRIP;
1335 : 0 : return enic_fm_append_action_op(fm, &fm_op, error);
1336 : : }
1337 : :
1338 : : /* Generate a reasonable source port number */
1339 : : static uint16_t
1340 : : gen_src_port(void)
1341 : : {
1342 : : /* Min/max below are the default values in OVS-DPDK and Linux */
1343 : 0 : uint16_t p = rte_rand();
1344 : 0 : p = RTE_MAX(p, 32768);
1345 : 0 : p = RTE_MIN(p, 61000);
1346 [ # # ]: 0 : return rte_cpu_to_be_16(p);
1347 : : }
1348 : :
1349 : : /* VXLAN encap is done via flowman compound action */
1350 : : static int
1351 : 0 : enic_fm_copy_vxlan_encap(struct enic_flowman *fm,
1352 : : const struct rte_flow_item *item,
1353 : : struct rte_flow_error *error)
1354 : : {
1355 : : struct fm_action_op fm_op;
1356 : : struct rte_ether_hdr *eth;
1357 : : struct rte_udp_hdr *udp;
1358 : : uint16_t *ethertype;
1359 : : void *template;
1360 : : uint8_t off;
1361 : :
1362 : 0 : ENICPMD_FUNC_TRACE();
1363 : : memset(&fm_op, 0, sizeof(fm_op));
1364 : 0 : fm_op.fa_op = FMOP_ENCAP;
1365 : 0 : template = fm->action.fma_data;
1366 : : off = 0;
1367 : : /*
1368 : : * Copy flow items to the flowman template starting L2.
1369 : : * L2 must be ethernet.
1370 : : */
1371 : : flow_item_skip_void(&item);
1372 [ # # ]: 0 : if (item->type != RTE_FLOW_ITEM_TYPE_ETH)
1373 : 0 : return rte_flow_error_set(error, EINVAL,
1374 : : RTE_FLOW_ERROR_TYPE_ITEM, item,
1375 : : "vxlan-encap: first item should be ethernet");
1376 : : eth = (struct rte_ether_hdr *)template;
1377 : : ethertype = ð->ether_type;
1378 : 0 : append_template(&template, &off, item->spec,
1379 : : sizeof(struct rte_ether_hdr));
1380 : 0 : item++;
1381 : : flow_item_skip_void(&item);
1382 : : /* Optional VLAN */
1383 [ # # ]: 0 : if (item->type == RTE_FLOW_ITEM_TYPE_VLAN) {
1384 : : const struct rte_flow_item_vlan *spec;
1385 : :
1386 : 0 : ENICPMD_LOG(DEBUG, "vxlan-encap: vlan");
1387 : 0 : spec = item->spec;
1388 [ # # ]: 0 : fm_op.encap.outer_vlan = rte_be_to_cpu_16(spec->hdr.vlan_tci);
1389 : 0 : item++;
1390 : : flow_item_skip_void(&item);
1391 : : }
1392 : : /* L3 must be IPv4, IPv6 */
1393 [ # # # ]: 0 : switch (item->type) {
1394 : 0 : case RTE_FLOW_ITEM_TYPE_IPV4:
1395 : : {
1396 : : struct rte_ipv4_hdr *ip4;
1397 : :
1398 : 0 : ENICPMD_LOG(DEBUG, "vxlan-encap: ipv4");
1399 : 0 : *ethertype = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4);
1400 : : ip4 = (struct rte_ipv4_hdr *)template;
1401 : : /*
1402 : : * Offset of IPv4 length field and its initial value
1403 : : * (IP + UDP + VXLAN) are specified in the action. The NIC
1404 : : * will add inner packet length.
1405 : : */
1406 : 0 : fm_op.encap.len1_offset = off +
1407 : : offsetof(struct rte_ipv4_hdr, total_length);
1408 : 0 : fm_op.encap.len1_delta = sizeof(struct rte_ipv4_hdr) +
1409 : : sizeof(struct rte_udp_hdr) +
1410 : : sizeof(struct rte_vxlan_hdr);
1411 [ # # ]: 0 : append_template(&template, &off, item->spec,
1412 : : sizeof(struct rte_ipv4_hdr));
1413 : 0 : ip4->version_ihl = RTE_IPV4_VHL_DEF;
1414 [ # # ]: 0 : if (ip4->time_to_live == 0)
1415 : 0 : ip4->time_to_live = IP_DEFTTL;
1416 : 0 : ip4->next_proto_id = IPPROTO_UDP;
1417 : 0 : break;
1418 : : }
1419 : 0 : case RTE_FLOW_ITEM_TYPE_IPV6:
1420 : : {
1421 : : struct rte_ipv6_hdr *ip6;
1422 : :
1423 : 0 : ENICPMD_LOG(DEBUG, "vxlan-encap: ipv6");
1424 : 0 : *ethertype = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV6);
1425 : : ip6 = (struct rte_ipv6_hdr *)template;
1426 : 0 : fm_op.encap.len1_offset = off +
1427 : : offsetof(struct rte_ipv6_hdr, payload_len);
1428 : 0 : fm_op.encap.len1_delta = sizeof(struct rte_udp_hdr) +
1429 : : sizeof(struct rte_vxlan_hdr);
1430 [ # # ]: 0 : append_template(&template, &off, item->spec,
1431 : : sizeof(struct rte_ipv6_hdr));
1432 : 0 : ip6->vtc_flow |= rte_cpu_to_be_32(IP6_VTC_FLOW);
1433 [ # # ]: 0 : if (ip6->hop_limits == 0)
1434 : 0 : ip6->hop_limits = IP_DEFTTL;
1435 : 0 : ip6->proto = IPPROTO_UDP;
1436 : 0 : break;
1437 : : }
1438 : 0 : default:
1439 : 0 : return rte_flow_error_set(error,
1440 : : EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, item,
1441 : : "vxlan-encap: L3 must be IPv4/IPv6");
1442 : : }
1443 : 0 : item++;
1444 : : flow_item_skip_void(&item);
1445 : :
1446 : : /* L4 is UDP */
1447 [ # # ]: 0 : if (item->type != RTE_FLOW_ITEM_TYPE_UDP)
1448 : 0 : return rte_flow_error_set(error, EINVAL,
1449 : : RTE_FLOW_ERROR_TYPE_ITEM, item,
1450 : : "vxlan-encap: UDP must follow IPv4/IPv6");
1451 : : /* UDP length = UDP + VXLAN. NIC will add inner packet length. */
1452 : 0 : fm_op.encap.len2_offset =
1453 : 0 : off + offsetof(struct rte_udp_hdr, dgram_len);
1454 : 0 : fm_op.encap.len2_delta =
1455 : : sizeof(struct rte_udp_hdr) + sizeof(struct rte_vxlan_hdr);
1456 : : udp = (struct rte_udp_hdr *)template;
1457 [ # # ]: 0 : append_template(&template, &off, item->spec,
1458 : : sizeof(struct rte_udp_hdr));
1459 : : /*
1460 : : * Firmware does not hash/fill source port yet. Generate a
1461 : : * random port, as there is *usually* one rte_flow for the
1462 : : * given inner packet stream (i.e. a single stream has one
1463 : : * random port).
1464 : : */
1465 [ # # ]: 0 : if (udp->src_port == 0)
1466 : 0 : udp->src_port = gen_src_port();
1467 : 0 : item++;
1468 : : flow_item_skip_void(&item);
1469 : :
1470 : : /* Finally VXLAN */
1471 [ # # ]: 0 : if (item->type != RTE_FLOW_ITEM_TYPE_VXLAN)
1472 : 0 : return rte_flow_error_set(error,
1473 : : EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, item,
1474 : : "vxlan-encap: VXLAN must follow UDP");
1475 : 0 : append_template(&template, &off, item->spec,
1476 : : sizeof(struct rte_flow_item_vxlan));
1477 : :
1478 : : /*
1479 : : * Fill in the rest of the action structure.
1480 : : * Indicate that we want to encap with vxlan at packet start.
1481 : : */
1482 : 0 : fm_op.encap.template_offset = 0;
1483 : 0 : fm_op.encap.template_len = off;
1484 : 0 : return enic_fm_append_action_op(fm, &fm_op, error);
1485 : : }
1486 : :
1487 : : static int
1488 : 0 : enic_fm_find_vnic(struct enic *enic, const struct rte_pci_addr *addr,
1489 : : uint64_t *handle)
1490 : : {
1491 : : uint32_t bdf;
1492 : : uint64_t args[2];
1493 : : int rc;
1494 : :
1495 : 0 : ENICPMD_FUNC_TRACE();
1496 : 0 : ENICPMD_LOG(DEBUG, "bdf=%x:%x:%x", addr->bus, addr->devid,
1497 : : addr->function);
1498 : 0 : bdf = addr->bus << 8 | addr->devid << 3 | addr->function;
1499 : 0 : args[0] = FM_VNIC_FIND;
1500 : 0 : args[1] = bdf;
1501 : 0 : rc = vnic_dev_flowman_cmd(enic->vdev, args, 2);
1502 [ # # ]: 0 : if (rc != 0) {
1503 : : /* Expected to fail if BDF is not on the adapter */
1504 : 0 : ENICPMD_LOG(DEBUG, "cannot find vnic handle: rc=%d", rc);
1505 : 0 : return rc;
1506 : : }
1507 : 0 : *handle = args[0];
1508 : 0 : ENICPMD_LOG(DEBUG, "found vnic: handle=0x%" PRIx64, *handle);
1509 : 0 : return 0;
1510 : : }
1511 : :
1512 : : /*
1513 : : * Egress: target port should be either PF uplink or VF.
1514 : : * Supported cases
1515 : : * 1. VF egress -> PF uplink
1516 : : * PF may be this VF's PF, or another PF, as long as they are on the same VIC.
1517 : : * 2. VF egress -> VF
1518 : : *
1519 : : * Unsupported cases
1520 : : * 1. PF egress -> VF
1521 : : * App should be using representor to pass packets to VF
1522 : : */
1523 : : static int
1524 : 0 : vf_egress_port_id_action(struct enic_flowman *fm,
1525 : : struct rte_eth_dev *dst_dev,
1526 : : uint64_t dst_vnic_h,
1527 : : struct fm_action_op *fm_op,
1528 : : struct rte_flow_error *error)
1529 : : {
1530 : : struct enic *src_enic, *dst_enic;
1531 : : struct enic_vf_representor *vf;
1532 : : uint8_t uif;
1533 : : int ret;
1534 : :
1535 : 0 : ENICPMD_FUNC_TRACE();
1536 [ # # ]: 0 : src_enic = fm->user_enic;
1537 : : dst_enic = pmd_priv(dst_dev);
1538 [ # # ]: 0 : if (!rte_eth_dev_is_repr(src_enic->rte_dev)) {
1539 : 0 : return rte_flow_error_set(error, EINVAL,
1540 : : RTE_FLOW_ERROR_TYPE_ACTION,
1541 : : NULL, "source port is not VF representor");
1542 : : }
1543 : :
1544 : : /* VF -> PF uplink. dst is not VF representor */
1545 [ # # ]: 0 : if (!rte_eth_dev_is_repr(dst_dev)) {
1546 : : /* PF is the VF's PF? Then nothing to do */
1547 : : vf = VF_ENIC_TO_VF_REP(src_enic);
1548 [ # # ]: 0 : if (vf->pf == dst_enic) {
1549 : 0 : ENICPMD_LOG(DEBUG, "destination port is VF's PF");
1550 : 0 : return 0;
1551 : : }
1552 : : /* If not, steer to the remote PF's uplink */
1553 : 0 : uif = dst_enic->fm_vnic_uif;
1554 : 0 : ENICPMD_LOG(DEBUG, "steer to uplink %u", uif);
1555 : : memset(fm_op, 0, sizeof(*fm_op));
1556 : 0 : fm_op->fa_op = FMOP_SET_EGPORT;
1557 : 0 : fm_op->set_egport.egport = uif;
1558 : 0 : ret = enic_fm_append_action_op(fm, fm_op, error);
1559 : 0 : return ret;
1560 : : }
1561 : :
1562 : : /* VF -> VF loopback. Hairpin and steer to vnic */
1563 : : memset(fm_op, 0, sizeof(*fm_op));
1564 : 0 : fm_op->fa_op = FMOP_EG_HAIRPIN;
1565 : 0 : ret = enic_fm_append_action_op(fm, fm_op, error);
1566 [ # # ]: 0 : if (ret)
1567 : : return ret;
1568 : 0 : ENICPMD_LOG(DEBUG, "egress hairpin");
1569 : 0 : fm->hairpin_steer_vnic_h = dst_vnic_h;
1570 : 0 : fm->need_hairpin_steer = 1;
1571 : 0 : return 0;
1572 : : }
1573 : :
1574 : : static int
1575 : 0 : enic_fm_check_transfer_dst(struct enic *enic, uint16_t dst_port_id,
1576 : : struct rte_eth_dev **dst_dev,
1577 : : struct rte_flow_error *error)
1578 : : {
1579 : : struct rte_eth_dev *dev;
1580 : :
1581 : 0 : ENICPMD_LOG(DEBUG, "port id %u", dst_port_id);
1582 [ # # ]: 0 : if (!rte_eth_dev_is_valid_port(dst_port_id)) {
1583 : 0 : return rte_flow_error_set(error, EINVAL,
1584 : : RTE_FLOW_ERROR_TYPE_ACTION,
1585 : : NULL, "invalid port_id");
1586 : : }
1587 : 0 : dev = &rte_eth_devices[dst_port_id];
1588 [ # # ]: 0 : if (!dev_is_enic(dev)) {
1589 : 0 : return rte_flow_error_set(error, EINVAL,
1590 : : RTE_FLOW_ERROR_TYPE_ACTION,
1591 : : NULL, "port_id is not enic");
1592 : : }
1593 [ # # ]: 0 : if (enic->switch_domain_id != pmd_priv(dev)->switch_domain_id) {
1594 : 0 : return rte_flow_error_set(error, EINVAL,
1595 : : RTE_FLOW_ERROR_TYPE_ACTION,
1596 : : NULL, "destination and source ports are not in the same switch domain");
1597 : : }
1598 : :
1599 : 0 : *dst_dev = dev;
1600 : 0 : return 0;
1601 : : }
1602 : :
1603 : : /* Translate flow actions to flowman TCAM entry actions */
1604 : : static int
1605 : 0 : enic_fm_copy_action(struct enic_flowman *fm,
1606 : : const struct rte_flow_action actions[],
1607 : : uint8_t ingress,
1608 : : struct rte_flow_error *error)
1609 : : {
1610 : : enum {
1611 : : FATE = 1 << 0,
1612 : : DECAP = 1 << 1,
1613 : : PASSTHRU = 1 << 2,
1614 : : COUNT = 1 << 3,
1615 : : ENCAP = 1 << 4,
1616 : : PUSH_VLAN = 1 << 5,
1617 : : PORT_ID = 1 << 6,
1618 : : };
1619 : : struct fm_tcam_match_entry *fmt;
1620 : : struct fm_action_op fm_op;
1621 : : bool need_ovlan_action;
1622 : : struct enic *enic;
1623 : : uint32_t overlap;
1624 : : uint64_t vnic_h;
1625 : : uint16_t ovlan;
1626 : : bool first_rq;
1627 : : bool steer;
1628 : : int ret;
1629 : :
1630 : 0 : ENICPMD_FUNC_TRACE();
1631 : 0 : fmt = &fm->tcam_entry;
1632 : : need_ovlan_action = false;
1633 : : ovlan = 0;
1634 : : first_rq = true;
1635 : : steer = false;
1636 : 0 : enic = fm->user_enic;
1637 : : overlap = 0;
1638 : 0 : vnic_h = enic->fm_vnic_handle;
1639 : :
1640 [ # # ]: 0 : for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) {
1641 [ # # # # : 0 : switch (actions->type) {
# # # # #
# # # # #
# # # #
# ]
1642 : 0 : case RTE_FLOW_ACTION_TYPE_VOID:
1643 : 0 : continue;
1644 : 0 : case RTE_FLOW_ACTION_TYPE_PASSTHRU: {
1645 [ # # ]: 0 : if (overlap & PASSTHRU)
1646 : 0 : goto unsupported;
1647 : 0 : overlap |= PASSTHRU;
1648 : 0 : break;
1649 : : }
1650 : 0 : case RTE_FLOW_ACTION_TYPE_JUMP: {
1651 : 0 : const struct rte_flow_action_jump *jump =
1652 : : actions->conf;
1653 : : struct enic_fm_fet *fet;
1654 : :
1655 [ # # ]: 0 : if (overlap & FATE)
1656 : 0 : goto unsupported;
1657 : 0 : ret = enic_fet_get(fm, jump->group, ingress, NULL,
1658 : : &fet, error);
1659 [ # # ]: 0 : if (ret)
1660 : 0 : return ret;
1661 : 0 : overlap |= FATE;
1662 : : memset(&fm_op, 0, sizeof(fm_op));
1663 : 0 : fm_op.fa_op = FMOP_EXACT_MATCH;
1664 : 0 : fm_op.exact.handle = fet->handle;
1665 : 0 : fm->fet = fet;
1666 : 0 : ret = enic_fm_append_action_op(fm, &fm_op, error);
1667 [ # # ]: 0 : if (ret)
1668 : 0 : return ret;
1669 : 0 : break;
1670 : : }
1671 : 0 : case RTE_FLOW_ACTION_TYPE_MARK: {
1672 : 0 : const struct rte_flow_action_mark *mark =
1673 : : actions->conf;
1674 : :
1675 [ # # ]: 0 : if (enic->use_noscatter_vec_rx_handler)
1676 : 0 : goto unsupported;
1677 [ # # ]: 0 : if (mark->id >= ENIC_MAGIC_FILTER_ID - 1)
1678 : 0 : return rte_flow_error_set(error, EINVAL,
1679 : : RTE_FLOW_ERROR_TYPE_ACTION,
1680 : : NULL, "invalid mark id");
1681 : : memset(&fm_op, 0, sizeof(fm_op));
1682 : 0 : fm_op.fa_op = FMOP_MARK;
1683 : 0 : fm_op.mark.mark = mark->id + 1;
1684 : 0 : ret = enic_fm_append_action_op(fm, &fm_op, error);
1685 [ # # ]: 0 : if (ret)
1686 : 0 : return ret;
1687 : : break;
1688 : : }
1689 : 0 : case RTE_FLOW_ACTION_TYPE_FLAG: {
1690 [ # # ]: 0 : if (enic->use_noscatter_vec_rx_handler)
1691 : 0 : goto unsupported;
1692 : : /* ENIC_MAGIC_FILTER_ID is reserved for flagging */
1693 : : memset(&fm_op, 0, sizeof(fm_op));
1694 : 0 : fm_op.fa_op = FMOP_MARK;
1695 : 0 : fm_op.mark.mark = ENIC_MAGIC_FILTER_ID;
1696 : 0 : ret = enic_fm_append_action_op(fm, &fm_op, error);
1697 [ # # ]: 0 : if (ret)
1698 : 0 : return ret;
1699 : : break;
1700 : : }
1701 : 0 : case RTE_FLOW_ACTION_TYPE_QUEUE: {
1702 : 0 : const struct rte_flow_action_queue *queue =
1703 : : actions->conf;
1704 : :
1705 : : /*
1706 : : * If fate other than QUEUE or RSS, fail. Multiple
1707 : : * rss and queue actions are ok.
1708 : : */
1709 [ # # # # ]: 0 : if ((overlap & FATE) && first_rq)
1710 : 0 : goto unsupported;
1711 : : first_rq = false;
1712 : 0 : overlap |= FATE;
1713 : : memset(&fm_op, 0, sizeof(fm_op));
1714 : 0 : fm_op.fa_op = FMOP_RQ_STEER;
1715 : 0 : fm_op.rq_steer.rq_index =
1716 : 0 : enic_rte_rq_idx_to_sop_idx(queue->index);
1717 : 0 : fm_op.rq_steer.rq_count = 1;
1718 : 0 : fm_op.rq_steer.vnic_handle = vnic_h;
1719 : 0 : ret = enic_fm_append_action_op(fm, &fm_op, error);
1720 [ # # ]: 0 : if (ret)
1721 : 0 : return ret;
1722 : 0 : ENICPMD_LOG(DEBUG, "create QUEUE action rq: %u",
1723 : : fm_op.rq_steer.rq_index);
1724 : : steer = true;
1725 : 0 : break;
1726 : : }
1727 : 0 : case RTE_FLOW_ACTION_TYPE_DROP: {
1728 [ # # ]: 0 : if (overlap & FATE)
1729 : 0 : goto unsupported;
1730 : 0 : overlap |= FATE;
1731 : : memset(&fm_op, 0, sizeof(fm_op));
1732 : 0 : fm_op.fa_op = FMOP_DROP;
1733 : 0 : ret = enic_fm_append_action_op(fm, &fm_op, error);
1734 [ # # ]: 0 : if (ret)
1735 : 0 : return ret;
1736 : 0 : ENICPMD_LOG(DEBUG, "create DROP action");
1737 : 0 : break;
1738 : : }
1739 : 0 : case RTE_FLOW_ACTION_TYPE_COUNT: {
1740 [ # # ]: 0 : if (overlap & COUNT)
1741 : 0 : goto unsupported;
1742 : 0 : overlap |= COUNT;
1743 : : /* Count is associated with entry not action on VIC. */
1744 : 0 : fmt->ftm_flags |= FMEF_COUNTER;
1745 : 0 : break;
1746 : : }
1747 : 0 : case RTE_FLOW_ACTION_TYPE_RSS: {
1748 : 0 : const struct rte_flow_action_rss *rss = actions->conf;
1749 : : bool allow;
1750 : : uint16_t i;
1751 : :
1752 : : /*
1753 : : * If fate other than QUEUE or RSS, fail. Multiple
1754 : : * rss and queue actions are ok.
1755 : : */
1756 [ # # # # ]: 0 : if ((overlap & FATE) && first_rq)
1757 : 0 : goto unsupported;
1758 : : first_rq = false;
1759 : 0 : overlap |= FATE;
1760 : :
1761 : : /*
1762 : : * Hardware only supports RSS actions on outer level
1763 : : * with default type and function. Queues must be
1764 : : * sequential.
1765 : : */
1766 : 0 : allow = rss->func == RTE_ETH_HASH_FUNCTION_DEFAULT &&
1767 [ # # ]: 0 : rss->level == 0 && (rss->types == 0 ||
1768 [ # # ]: 0 : rss->types == enic->rss_hf) &&
1769 [ # # # # ]: 0 : rss->queue_num <= enic->rq_count &&
1770 [ # # ]: 0 : rss->queue[rss->queue_num - 1] < enic->rq_count;
1771 : :
1772 : :
1773 : : /* Identity queue map needs to be sequential */
1774 [ # # ]: 0 : for (i = 1; i < rss->queue_num; i++)
1775 [ # # ]: 0 : allow = allow && (rss->queue[i] ==
1776 [ # # ]: 0 : rss->queue[i - 1] + 1);
1777 [ # # ]: 0 : if (!allow)
1778 : 0 : goto unsupported;
1779 : :
1780 : : memset(&fm_op, 0, sizeof(fm_op));
1781 : 0 : fm_op.fa_op = FMOP_RQ_STEER;
1782 : 0 : fm_op.rq_steer.rq_index =
1783 : 0 : enic_rte_rq_idx_to_sop_idx(rss->queue[0]);
1784 : 0 : fm_op.rq_steer.rq_count = rss->queue_num;
1785 : 0 : fm_op.rq_steer.vnic_handle = vnic_h;
1786 : 0 : ret = enic_fm_append_action_op(fm, &fm_op, error);
1787 [ # # ]: 0 : if (ret)
1788 : 0 : return ret;
1789 : 0 : ENICPMD_LOG(DEBUG, "create QUEUE action rq: %u",
1790 : : fm_op.rq_steer.rq_index);
1791 : : steer = true;
1792 : 0 : break;
1793 : : }
1794 : 0 : case RTE_FLOW_ACTION_TYPE_PORT_ID: {
1795 : : const struct rte_flow_action_port_id *port;
1796 : 0 : struct rte_eth_dev *dev = NULL;
1797 : :
1798 [ # # # # ]: 0 : if (!ingress && (overlap & PORT_ID)) {
1799 : 0 : ENICPMD_LOG(DEBUG, "cannot have multiple egress PORT_ID actions");
1800 : 0 : goto unsupported;
1801 : : }
1802 : 0 : port = actions->conf;
1803 [ # # ]: 0 : if (port->original) {
1804 : 0 : vnic_h = enic->fm_vnic_handle; /* This port */
1805 : 0 : break;
1806 : : }
1807 : 0 : ret = enic_fm_check_transfer_dst(enic, port->id, &dev,
1808 : : error);
1809 [ # # ]: 0 : if (ret)
1810 : 0 : return ret;
1811 [ # # ]: 0 : vnic_h = pmd_priv(dev)->fm_vnic_handle;
1812 : 0 : overlap |= PORT_ID;
1813 : : /*
1814 : : * Ingress. Nothing more to do. We add an implicit
1815 : : * steer at the end if needed.
1816 : : */
1817 [ # # ]: 0 : if (ingress)
1818 : : break;
1819 : : /* Egress */
1820 : 0 : ret = vf_egress_port_id_action(fm, dev, vnic_h, &fm_op,
1821 : : error);
1822 [ # # ]: 0 : if (ret)
1823 : 0 : return ret;
1824 : : break;
1825 : : }
1826 : 0 : case RTE_FLOW_ACTION_TYPE_VXLAN_DECAP: {
1827 [ # # ]: 0 : if (overlap & DECAP)
1828 : 0 : goto unsupported;
1829 : 0 : overlap |= DECAP;
1830 : :
1831 : 0 : ret = enic_fm_copy_vxlan_decap(fm, fmt, actions,
1832 : : error);
1833 [ # # ]: 0 : if (ret != 0)
1834 : 0 : return ret;
1835 : : break;
1836 : : }
1837 : 0 : case RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP: {
1838 : : const struct rte_flow_action_vxlan_encap *encap;
1839 : :
1840 : 0 : encap = actions->conf;
1841 [ # # ]: 0 : if (overlap & ENCAP)
1842 : 0 : goto unsupported;
1843 : 0 : overlap |= ENCAP;
1844 : 0 : ret = enic_fm_copy_vxlan_encap(fm, encap->definition,
1845 : : error);
1846 [ # # ]: 0 : if (ret != 0)
1847 : 0 : return ret;
1848 : : break;
1849 : : }
1850 : : case RTE_FLOW_ACTION_TYPE_OF_POP_VLAN: {
1851 : : struct fm_action_op *decap;
1852 : :
1853 : : /*
1854 : : * If decap-nostrip appears before pop vlan, this pop
1855 : : * applies to the inner packet vlan. Turn it into
1856 : : * decap-strip.
1857 : : */
1858 : : decap = find_prev_action_op(fm, FMOP_DECAP_NOSTRIP);
1859 [ # # ]: 0 : if (decap) {
1860 : 0 : ENICPMD_LOG(DEBUG, "pop-vlan inner: decap-nostrip => decap-strip");
1861 : 0 : decap->fa_op = FMOP_DECAP_STRIP;
1862 : 0 : break;
1863 : : }
1864 : : memset(&fm_op, 0, sizeof(fm_op));
1865 : 0 : fm_op.fa_op = FMOP_POP_VLAN;
1866 : 0 : ret = enic_fm_append_action_op(fm, &fm_op, error);
1867 [ # # ]: 0 : if (ret)
1868 : 0 : return ret;
1869 : : break;
1870 : : }
1871 : 0 : case RTE_FLOW_ACTION_TYPE_OF_PUSH_VLAN: {
1872 : : const struct rte_flow_action_of_push_vlan *vlan;
1873 : :
1874 [ # # ]: 0 : if (overlap & PASSTHRU)
1875 : 0 : goto unsupported;
1876 : 0 : vlan = actions->conf;
1877 [ # # ]: 0 : if (vlan->ethertype != RTE_BE16(RTE_ETHER_TYPE_VLAN)) {
1878 : 0 : return rte_flow_error_set(error, EINVAL,
1879 : : RTE_FLOW_ERROR_TYPE_ACTION,
1880 : : NULL, "unexpected push_vlan ethertype");
1881 : : }
1882 : 0 : overlap |= PUSH_VLAN;
1883 : : need_ovlan_action = true;
1884 : 0 : break;
1885 : : }
1886 : 0 : case RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_PCP: {
1887 : : const struct rte_flow_action_of_set_vlan_pcp *pcp;
1888 : :
1889 : 0 : pcp = actions->conf;
1890 [ # # ]: 0 : if (pcp->vlan_pcp > 7) {
1891 : 0 : return rte_flow_error_set(error, EINVAL,
1892 : : RTE_FLOW_ERROR_TYPE_ACTION,
1893 : : NULL, "invalid vlan_pcp");
1894 : : }
1895 : : need_ovlan_action = true;
1896 : 0 : ovlan |= ((uint16_t)pcp->vlan_pcp) << 13;
1897 : 0 : break;
1898 : : }
1899 : 0 : case RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID: {
1900 : : const struct rte_flow_action_of_set_vlan_vid *vid;
1901 : :
1902 : 0 : vid = actions->conf;
1903 : : need_ovlan_action = true;
1904 [ # # ]: 0 : ovlan |= rte_be_to_cpu_16(vid->vlan_vid);
1905 : 0 : break;
1906 : : }
1907 : 0 : case RTE_FLOW_ACTION_TYPE_PORT_REPRESENTOR: {
1908 : : const struct rte_flow_action_ethdev *ethdev;
1909 : 0 : struct rte_eth_dev *dev = NULL;
1910 : :
1911 : 0 : ethdev = actions->conf;
1912 : 0 : ret = enic_fm_check_transfer_dst(enic, ethdev->port_id,
1913 : : &dev, error);
1914 [ # # ]: 0 : if (ret)
1915 : 0 : return ret;
1916 : 0 : vnic_h = pmd_priv(dev)->fm_vnic_handle;
1917 : 0 : overlap |= PORT_ID;
1918 : : /*
1919 : : * Action PORT_REPRESENTOR implies ingress destination.
1920 : : * Noting to do. We add an implicit stree at the
1921 : : * end if needed.
1922 : : */
1923 : : ingress = 1;
1924 : 0 : break;
1925 : : }
1926 : 0 : case RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT: {
1927 : : const struct rte_flow_action_ethdev *ethdev;
1928 : 0 : struct rte_eth_dev *dev = NULL;
1929 : :
1930 [ # # ]: 0 : if (overlap & PORT_ID) {
1931 : 0 : ENICPMD_LOG(DEBUG, "cannot have multiple egress PORT_ID actions");
1932 : 0 : goto unsupported;
1933 : : }
1934 : 0 : ethdev = actions->conf;
1935 : 0 : ret = enic_fm_check_transfer_dst(enic, ethdev->port_id,
1936 : : &dev, error);
1937 [ # # ]: 0 : if (ret)
1938 : 0 : return ret;
1939 : 0 : vnic_h = pmd_priv(dev)->fm_vnic_handle;
1940 : 0 : overlap |= PORT_ID;
1941 : : /* Action REPRESENTED_PORT: always egress destination */
1942 : : ingress = 0;
1943 : 0 : ret = vf_egress_port_id_action(fm, dev, vnic_h, &fm_op,
1944 : : error);
1945 [ # # ]: 0 : if (ret)
1946 : 0 : return ret;
1947 : 0 : break;
1948 : : }
1949 : 0 : default:
1950 : 0 : goto unsupported;
1951 : : }
1952 : : }
1953 : :
1954 [ # # ]: 0 : if (!(overlap & (FATE | PASSTHRU | COUNT | PORT_ID)))
1955 : 0 : goto unsupported;
1956 : : /* Egress from VF: need implicit WQ match */
1957 [ # # # # ]: 0 : if (rte_eth_dev_is_repr(enic->rte_dev) && !ingress) {
1958 : 0 : fmt->ftm_data.fk_wq_id = 0;
1959 : 0 : fmt->ftm_mask.fk_wq_id = 0xffff;
1960 : 0 : fmt->ftm_data.fk_wq_vnic = enic->fm_vnic_handle;
1961 : 0 : ENICPMD_LOG(DEBUG, "add implicit wq id match for vf %d",
1962 : : VF_ENIC_TO_VF_REP(enic)->vf_id);
1963 : : }
1964 [ # # ]: 0 : if (need_ovlan_action) {
1965 : : memset(&fm_op, 0, sizeof(fm_op));
1966 : 0 : fm_op.fa_op = FMOP_SET_OVLAN;
1967 : 0 : fm_op.ovlan.vlan = ovlan;
1968 : 0 : ret = enic_fm_append_action_op(fm, &fm_op, error);
1969 [ # # ]: 0 : if (ret)
1970 : : return ret;
1971 : : }
1972 : : /* Add steer op for PORT_ID without QUEUE */
1973 [ # # # # ]: 0 : if ((overlap & PORT_ID) && !steer && ingress) {
1974 : : memset(&fm_op, 0, sizeof(fm_op));
1975 : : /* Always to queue 0 for now as generic RSS is not available */
1976 : 0 : fm_op.fa_op = FMOP_RQ_STEER;
1977 : : fm_op.rq_steer.rq_index = 0;
1978 : 0 : fm_op.rq_steer.vnic_handle = vnic_h;
1979 : 0 : ret = enic_fm_append_action_op(fm, &fm_op, error);
1980 [ # # ]: 0 : if (ret)
1981 : : return ret;
1982 : 0 : ENICPMD_LOG(DEBUG, "add implicit steer op");
1983 : : }
1984 : : /* Add required END */
1985 : : memset(&fm_op, 0, sizeof(fm_op));
1986 : 0 : fm_op.fa_op = FMOP_END;
1987 : 0 : ret = enic_fm_append_action_op(fm, &fm_op, error);
1988 [ # # ]: 0 : if (ret)
1989 : : return ret;
1990 : 0 : enic_fm_reorder_action_op(fm);
1991 : 0 : return 0;
1992 : :
1993 : 0 : unsupported:
1994 : 0 : return rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION,
1995 : : NULL, "enic: unsupported action");
1996 : : }
1997 : :
1998 : : /** Check if the action is supported */
1999 : : static int
2000 : : enic_fm_match_action(const struct rte_flow_action *action,
2001 : : const enum rte_flow_action_type *supported_actions)
2002 : : {
2003 [ # # ]: 0 : for (; *supported_actions != RTE_FLOW_ACTION_TYPE_END;
2004 : 0 : supported_actions++) {
2005 [ # # ]: 0 : if (action->type == *supported_actions)
2006 : : return 1;
2007 : : }
2008 : : return 0;
2009 : : }
2010 : :
2011 : : /* Debug function to dump internal NIC action structure. */
2012 : : static void
2013 : 0 : enic_fm_dump_tcam_actions(const struct fm_action *fm_action)
2014 : : {
2015 : : /* Manually keep in sync with FMOP commands */
2016 : 0 : const char *fmop_str[FMOP_OP_MAX] = {
2017 : : [FMOP_END] = "end",
2018 : : [FMOP_DROP] = "drop",
2019 : : [FMOP_RQ_STEER] = "steer",
2020 : : [FMOP_EXACT_MATCH] = "exmatch",
2021 : : [FMOP_MARK] = "mark",
2022 : : [FMOP_EXT_MARK] = "ext_mark",
2023 : : [FMOP_TAG] = "tag",
2024 : : [FMOP_EG_HAIRPIN] = "eg_hairpin",
2025 : : [FMOP_IG_HAIRPIN] = "ig_hairpin",
2026 : : [FMOP_ENCAP_IVLAN] = "encap_ivlan",
2027 : : [FMOP_ENCAP_NOIVLAN] = "encap_noivlan",
2028 : : [FMOP_ENCAP] = "encap",
2029 : : [FMOP_SET_OVLAN] = "set_ovlan",
2030 : : [FMOP_DECAP_NOSTRIP] = "decap_nostrip",
2031 : : [FMOP_DECAP_STRIP] = "decap_strip",
2032 : : [FMOP_POP_VLAN] = "pop_vlan",
2033 : : [FMOP_SET_EGPORT] = "set_egport",
2034 : : [FMOP_RQ_STEER_ONLY] = "rq_steer_only",
2035 : : [FMOP_SET_ENCAP_VLAN] = "set_encap_vlan",
2036 : : [FMOP_EMIT] = "emit",
2037 : : [FMOP_MODIFY] = "modify",
2038 : : };
2039 : 0 : const struct fm_action_op *op = &fm_action->fma_action_ops[0];
2040 : : char buf[128], *bp = buf;
2041 : : const char *op_str;
2042 : : int i, n, buf_len;
2043 : :
2044 : 0 : buf[0] = '\0';
2045 : : buf_len = sizeof(buf);
2046 [ # # ]: 0 : for (i = 0; i < FM_ACTION_OP_MAX; i++) {
2047 [ # # ]: 0 : if (op->fa_op == FMOP_END)
2048 : : break;
2049 [ # # ]: 0 : if (op->fa_op >= FMOP_OP_MAX)
2050 : : op_str = "unknown";
2051 : : else
2052 : 0 : op_str = fmop_str[op->fa_op];
2053 [ # # ]: 0 : n = snprintf(bp, buf_len, "%s,", op_str);
2054 [ # # ]: 0 : if (n > 0 && n < buf_len) {
2055 : 0 : bp += n;
2056 : 0 : buf_len -= n;
2057 : : }
2058 : 0 : op++;
2059 : : }
2060 : : /* Remove trailing comma */
2061 [ # # ]: 0 : if (buf[0])
2062 : 0 : *(bp - 1) = '\0';
2063 : 0 : ENICPMD_LOG(DEBUG, " Actions: %s", buf);
2064 : 0 : }
2065 : :
2066 : : static int
2067 : 0 : bits_to_str(uint32_t bits, const char *strings[], int max,
2068 : : char *buf, int buf_len)
2069 : : {
2070 : : int i, n = 0, len = 0;
2071 : :
2072 [ # # ]: 0 : for (i = 0; i < max; i++) {
2073 [ # # ]: 0 : if (bits & (1 << i)) {
2074 [ # # ]: 0 : n = snprintf(buf, buf_len, "%s,", strings[i]);
2075 [ # # ]: 0 : if (n > 0 && n < buf_len) {
2076 : 0 : buf += n;
2077 : 0 : buf_len -= n;
2078 : 0 : len += n;
2079 : : }
2080 : : }
2081 : : }
2082 : : /* Remove trailing comma */
2083 [ # # ]: 0 : if (len) {
2084 : 0 : *(buf - 1) = '\0';
2085 : 0 : len--;
2086 : : }
2087 : 0 : return len;
2088 : : }
2089 : :
2090 : : /* Debug function to dump internal NIC filter structure. */
2091 : : static void
2092 : 0 : __enic_fm_dump_tcam_match(const struct fm_header_set *fk_hdrset, char *buf,
2093 : : int buf_len)
2094 : : {
2095 : : /* Manually keep in sync with FKM_BITS */
2096 : 0 : const char *fm_fkm_str[FKM_BIT_COUNT] = {
2097 : : [FKM_QTAG_BIT] = "qtag",
2098 : : [FKM_CMD_BIT] = "cmd",
2099 : : [FKM_IPV4_BIT] = "ip4",
2100 : : [FKM_IPV6_BIT] = "ip6",
2101 : : [FKM_ROCE_BIT] = "roce",
2102 : : [FKM_UDP_BIT] = "udp",
2103 : : [FKM_TCP_BIT] = "tcp",
2104 : : [FKM_TCPORUDP_BIT] = "tcpportudp",
2105 : : [FKM_IPFRAG_BIT] = "ipfrag",
2106 : : [FKM_NVGRE_BIT] = "nvgre",
2107 : : [FKM_VXLAN_BIT] = "vxlan",
2108 : : [FKM_GENEVE_BIT] = "geneve",
2109 : : [FKM_NSH_BIT] = "nsh",
2110 : : [FKM_ROCEV2_BIT] = "rocev2",
2111 : : [FKM_VLAN_PRES_BIT] = "vlan_pres",
2112 : : [FKM_IPOK_BIT] = "ipok",
2113 : : [FKM_L4OK_BIT] = "l4ok",
2114 : : [FKM_ROCEOK_BIT] = "roceok",
2115 : : [FKM_FCSOK_BIT] = "fcsok",
2116 : : [FKM_EG_SPAN_BIT] = "eg_span",
2117 : : [FKM_IG_SPAN_BIT] = "ig_span",
2118 : : [FKM_EG_HAIRPINNED_BIT] = "eg_hairpinned",
2119 : : };
2120 : : /* Manually keep in sync with FKH_BITS */
2121 : 0 : const char *fm_fkh_str[FKH_BIT_COUNT] = {
2122 : : [FKH_ETHER_BIT] = "eth",
2123 : : [FKH_QTAG_BIT] = "qtag",
2124 : : [FKH_L2RAW_BIT] = "l2raw",
2125 : : [FKH_IPV4_BIT] = "ip4",
2126 : : [FKH_IPV6_BIT] = "ip6",
2127 : : [FKH_L3RAW_BIT] = "l3raw",
2128 : : [FKH_UDP_BIT] = "udp",
2129 : : [FKH_TCP_BIT] = "tcp",
2130 : : [FKH_ICMP_BIT] = "icmp",
2131 : : [FKH_VXLAN_BIT] = "vxlan",
2132 : : [FKH_L4RAW_BIT] = "l4raw",
2133 : : };
2134 : 0 : uint32_t fkh_bits = fk_hdrset->fk_header_select;
2135 : 0 : uint32_t fkm_bits = fk_hdrset->fk_metadata;
2136 : : int n;
2137 : :
2138 [ # # ]: 0 : if (!fkm_bits && !fkh_bits)
2139 : 0 : return;
2140 [ # # ]: 0 : n = snprintf(buf, buf_len, "metadata(");
2141 [ # # ]: 0 : if (n > 0 && n < buf_len) {
2142 : 0 : buf += n;
2143 : 0 : buf_len -= n;
2144 : : }
2145 : 0 : n = bits_to_str(fkm_bits, fm_fkm_str, FKM_BIT_COUNT, buf, buf_len);
2146 [ # # ]: 0 : if (n > 0 && n < buf_len) {
2147 : 0 : buf += n;
2148 : 0 : buf_len -= n;
2149 : : }
2150 [ # # ]: 0 : n = snprintf(buf, buf_len, ") valid hdr fields(");
2151 [ # # ]: 0 : if (n > 0 && n < buf_len) {
2152 : 0 : buf += n;
2153 : 0 : buf_len -= n;
2154 : : }
2155 : 0 : n = bits_to_str(fkh_bits, fm_fkh_str, FKH_BIT_COUNT, buf, buf_len);
2156 [ # # ]: 0 : if (n > 0 && n < buf_len) {
2157 : 0 : buf += n;
2158 : 0 : buf_len -= n;
2159 : : }
2160 : 0 : snprintf(buf, buf_len, ")");
2161 : : }
2162 : :
2163 : : static void
2164 : 0 : enic_fm_dump_tcam_match(const struct fm_tcam_match_entry *match,
2165 : : uint8_t ingress)
2166 : : {
2167 : : char buf[256];
2168 : :
2169 : : memset(buf, 0, sizeof(buf));
2170 : 0 : __enic_fm_dump_tcam_match(&match->ftm_mask.fk_hdrset[0],
2171 : : buf, sizeof(buf));
2172 [ # # # # ]: 0 : ENICPMD_LOG(DEBUG, " TCAM %s Outer: %s %scounter position %u",
2173 : : (ingress) ? "IG" : "EG", buf,
2174 : : (match->ftm_flags & FMEF_COUNTER) ? "" : "no ",
2175 : : match->ftm_position);
2176 : : memset(buf, 0, sizeof(buf));
2177 : 0 : __enic_fm_dump_tcam_match(&match->ftm_mask.fk_hdrset[1],
2178 : : buf, sizeof(buf));
2179 [ # # ]: 0 : if (buf[0])
2180 : 0 : ENICPMD_LOG(DEBUG, " Inner: %s", buf);
2181 : 0 : }
2182 : :
2183 : : /* Debug function to dump internal NIC flow structures. */
2184 : : static void
2185 : 0 : enic_fm_dump_tcam_entry(const struct fm_tcam_match_entry *fm_match,
2186 : : const struct fm_action *fm_action,
2187 : : uint8_t ingress)
2188 : : {
2189 [ # # ]: 0 : if (!rte_log_can_log(enic_pmd_logtype, RTE_LOG_DEBUG))
2190 : : return;
2191 : 0 : enic_fm_dump_tcam_match(fm_match, ingress);
2192 : 0 : enic_fm_dump_tcam_actions(fm_action);
2193 : : }
2194 : :
2195 : : static int
2196 : 0 : enic_fm_flow_parse(struct enic_flowman *fm,
2197 : : const struct rte_flow_attr *attrs,
2198 : : const struct rte_flow_item pattern[],
2199 : : const struct rte_flow_action actions[],
2200 : : struct rte_flow_error *error)
2201 : : {
2202 : : const struct rte_flow_action *action;
2203 : : unsigned int ret;
2204 : : static const enum rte_flow_action_type *sa;
2205 : :
2206 : 0 : ENICPMD_FUNC_TRACE();
2207 : : ret = 0;
2208 [ # # ]: 0 : if (!pattern) {
2209 : 0 : rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM_NUM,
2210 : : NULL, "no pattern specified");
2211 : 0 : return -rte_errno;
2212 : : }
2213 : :
2214 [ # # ]: 0 : if (!actions) {
2215 : 0 : rte_flow_error_set(error, EINVAL,
2216 : : RTE_FLOW_ERROR_TYPE_ACTION_NUM,
2217 : : NULL, "no action specified");
2218 : 0 : return -rte_errno;
2219 : : }
2220 : :
2221 [ # # ]: 0 : if (attrs) {
2222 [ # # # # ]: 0 : if (attrs->group != FM_TCAM_RTE_GROUP && attrs->priority) {
2223 : 0 : rte_flow_error_set(error, ENOTSUP,
2224 : : RTE_FLOW_ERROR_TYPE_ATTR_PRIORITY,
2225 : : NULL,
2226 : : "priorities are not supported for non-default (0) groups");
2227 : 0 : return -rte_errno;
2228 [ # # # # ]: 0 : } else if (!fm->owner_enic->switchdev_mode && attrs->transfer) {
2229 : 0 : rte_flow_error_set(error, ENOTSUP,
2230 : : RTE_FLOW_ERROR_TYPE_ATTR_TRANSFER,
2231 : : NULL,
2232 : : "transfer is not supported");
2233 : 0 : return -rte_errno;
2234 [ # # ]: 0 : } else if (attrs->ingress && attrs->egress) {
2235 : 0 : rte_flow_error_set(error, ENOTSUP,
2236 : : RTE_FLOW_ERROR_TYPE_ATTR_INGRESS,
2237 : : NULL,
2238 : : "bidirectional rules not supported");
2239 : 0 : return -rte_errno;
2240 : : }
2241 : :
2242 : : } else {
2243 : 0 : rte_flow_error_set(error, EINVAL,
2244 : : RTE_FLOW_ERROR_TYPE_ATTR,
2245 : : NULL, "no attribute specified");
2246 : 0 : return -rte_errno;
2247 : : }
2248 : :
2249 : : /* Verify Actions. */
2250 [ # # ]: 0 : sa = (attrs->ingress) ? enic_fm_supported_ig_actions :
2251 : : enic_fm_supported_eg_actions;
2252 [ # # ]: 0 : for (action = &actions[0]; action->type != RTE_FLOW_ACTION_TYPE_END;
2253 : 0 : action++) {
2254 [ # # ]: 0 : if (action->type == RTE_FLOW_ACTION_TYPE_VOID)
2255 : 0 : continue;
2256 [ # # ]: 0 : else if (!enic_fm_match_action(action, sa))
2257 : : break;
2258 : : }
2259 [ # # ]: 0 : if (action->type != RTE_FLOW_ACTION_TYPE_END) {
2260 : 0 : rte_flow_error_set(error, EPERM, RTE_FLOW_ERROR_TYPE_ACTION,
2261 : : action, "invalid action");
2262 : 0 : return -rte_errno;
2263 : : }
2264 : 0 : ret = enic_fm_copy_entry(fm, pattern, error);
2265 [ # # ]: 0 : if (ret)
2266 : : return ret;
2267 : 0 : ret = enic_fm_copy_action(fm, actions, attrs->ingress, error);
2268 : 0 : return ret;
2269 : : }
2270 : :
2271 : : static void
2272 : : enic_fm_counter_free(struct enic_flowman *fm, struct enic_fm_flow *fm_flow)
2273 : : {
2274 [ # # ]: 0 : if (!fm_flow->counter_valid)
2275 : : return;
2276 : 0 : SLIST_INSERT_HEAD(&fm->counters, fm_flow->counter, next);
2277 : 0 : fm_flow->counter_valid = false;
2278 : : }
2279 : :
2280 : : static int
2281 : 0 : enic_fm_more_counters(struct enic_flowman *fm)
2282 : : {
2283 : : struct enic_fm_counter *new_stack;
2284 : : struct enic_fm_counter *ctrs;
2285 : : int i, rc;
2286 : : uint64_t args[2];
2287 : :
2288 : 0 : ENICPMD_FUNC_TRACE();
2289 : 0 : new_stack = rte_realloc(fm->counter_stack, (fm->counters_alloced +
2290 : : FM_COUNTERS_EXPAND) *
2291 : : sizeof(struct enic_fm_counter), 0);
2292 [ # # ]: 0 : if (new_stack == NULL) {
2293 : 0 : ENICPMD_LOG(ERR, "cannot alloc counter memory");
2294 : 0 : return -ENOMEM;
2295 : : }
2296 : 0 : fm->counter_stack = new_stack;
2297 : :
2298 : 0 : args[0] = FM_COUNTER_BRK;
2299 : 0 : args[1] = fm->counters_alloced + FM_COUNTERS_EXPAND;
2300 : : rc = flowman_cmd(fm, args, 2);
2301 [ # # ]: 0 : if (rc != 0) {
2302 : 0 : ENICPMD_LOG(ERR, "cannot alloc counters rc=%d", rc);
2303 : 0 : return rc;
2304 : : }
2305 : 0 : ctrs = (struct enic_fm_counter *)fm->counter_stack +
2306 : 0 : fm->counters_alloced;
2307 [ # # ]: 0 : for (i = 0; i < FM_COUNTERS_EXPAND; i++, ctrs++) {
2308 : 0 : ctrs->handle = fm->counters_alloced + i;
2309 : 0 : SLIST_INSERT_HEAD(&fm->counters, ctrs, next);
2310 : : }
2311 : 0 : fm->counters_alloced += FM_COUNTERS_EXPAND;
2312 : 0 : ENICPMD_LOG(DEBUG, "%u counters allocated, total: %u",
2313 : : FM_COUNTERS_EXPAND, fm->counters_alloced);
2314 : 0 : return 0;
2315 : : }
2316 : :
2317 : : static int
2318 : 0 : enic_fm_counter_zero(struct enic_flowman *fm, struct enic_fm_counter *c)
2319 : : {
2320 : : uint64_t args[3];
2321 : : int ret;
2322 : :
2323 : 0 : ENICPMD_FUNC_TRACE();
2324 : 0 : args[0] = FM_COUNTER_QUERY;
2325 : 0 : args[1] = c->handle;
2326 : 0 : args[2] = 1; /* clear */
2327 : : ret = flowman_cmd(fm, args, 3);
2328 [ # # ]: 0 : if (ret) {
2329 : 0 : ENICPMD_LOG(ERR, "counter init: rc=%d handle=0x%x",
2330 : : ret, c->handle);
2331 : 0 : return ret;
2332 : : }
2333 : : return 0;
2334 : : }
2335 : :
2336 : : static int
2337 : 0 : enic_fm_counter_alloc(struct enic_flowman *fm, struct rte_flow_error *error,
2338 : : struct enic_fm_counter **ctr)
2339 : : {
2340 : : struct enic_fm_counter *c;
2341 : : int ret;
2342 : :
2343 : 0 : ENICPMD_FUNC_TRACE();
2344 : 0 : *ctr = NULL;
2345 [ # # ]: 0 : if (SLIST_EMPTY(&fm->counters)) {
2346 : 0 : ret = enic_fm_more_counters(fm);
2347 [ # # ]: 0 : if (ret)
2348 : 0 : return rte_flow_error_set(error, -ret,
2349 : : RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
2350 : : NULL, "enic: out of counters");
2351 : : }
2352 : 0 : c = SLIST_FIRST(&fm->counters);
2353 : 0 : SLIST_REMOVE_HEAD(&fm->counters, next);
2354 : 0 : *ctr = c;
2355 : 0 : return 0;
2356 : : }
2357 : :
2358 : : static int
2359 : 0 : enic_fm_action_free(struct enic_flowman *fm, struct enic_fm_action *ah)
2360 : : {
2361 : : uint64_t args[2];
2362 : : int ret = 0;
2363 : :
2364 : 0 : ENICPMD_FUNC_TRACE();
2365 : : RTE_ASSERT(ah->ref > 0);
2366 : 0 : ah->ref--;
2367 [ # # ]: 0 : if (ah->ref == 0) {
2368 : 0 : args[0] = FM_ACTION_FREE;
2369 : 0 : args[1] = ah->handle;
2370 : : ret = flowman_cmd(fm, args, 2);
2371 [ # # ]: 0 : if (ret)
2372 : : /* This is a "should never happen" error. */
2373 : 0 : ENICPMD_LOG(ERR, "freeing action rc=%d handle=0x%"
2374 : : PRIx64, ret, ah->handle);
2375 : 0 : rte_hash_del_key(fm->action_hash, (const void *)&ah->key);
2376 : 0 : free(ah);
2377 : : }
2378 : 0 : return ret;
2379 : : }
2380 : :
2381 : : static int
2382 : 0 : enic_fm_entry_free(struct enic_flowman *fm, uint64_t handle)
2383 : : {
2384 : : uint64_t args[2];
2385 : : int rc;
2386 : :
2387 : 0 : ENICPMD_FUNC_TRACE();
2388 : 0 : args[0] = FM_MATCH_ENTRY_REMOVE;
2389 : 0 : args[1] = handle;
2390 : : rc = flowman_cmd(fm, args, 2);
2391 [ # # ]: 0 : if (rc)
2392 : 0 : ENICPMD_LOG(ERR, "cannot free match entry: rc=%d"
2393 : : " handle=0x%" PRIx64, rc, handle);
2394 : 0 : return rc;
2395 : : }
2396 : :
2397 : : static struct enic_fm_jump_flow *
2398 : 0 : find_jump_flow(struct enic_flowman *fm, uint32_t group)
2399 : : {
2400 : : struct enic_fm_jump_flow *j;
2401 : :
2402 : 0 : ENICPMD_FUNC_TRACE();
2403 [ # # ]: 0 : TAILQ_FOREACH(j, &fm->jump_list, list) {
2404 [ # # ]: 0 : if (j->group == group)
2405 : 0 : return j;
2406 : : }
2407 : : return NULL;
2408 : : }
2409 : :
2410 : : static void
2411 : 0 : remove_jump_flow(struct enic_flowman *fm, struct rte_flow *flow)
2412 : : {
2413 : : struct enic_fm_jump_flow *j;
2414 : :
2415 : 0 : ENICPMD_FUNC_TRACE();
2416 [ # # ]: 0 : TAILQ_FOREACH(j, &fm->jump_list, list) {
2417 [ # # ]: 0 : if (j->flow == flow) {
2418 [ # # ]: 0 : TAILQ_REMOVE(&fm->jump_list, j, list);
2419 : 0 : free(j);
2420 : 0 : return;
2421 : : }
2422 : : }
2423 : : }
2424 : :
2425 : : static int
2426 : 0 : save_jump_flow(struct enic_flowman *fm,
2427 : : struct rte_flow *flow,
2428 : : uint32_t group,
2429 : : struct fm_tcam_match_entry *match,
2430 : : struct fm_action *action)
2431 : : {
2432 : : struct enic_fm_jump_flow *j;
2433 : :
2434 : 0 : ENICPMD_FUNC_TRACE();
2435 : 0 : j = calloc(1, sizeof(struct enic_fm_jump_flow));
2436 [ # # ]: 0 : if (j == NULL)
2437 : : return -ENOMEM;
2438 : 0 : j->flow = flow;
2439 : 0 : j->group = group;
2440 : 0 : j->match = *match;
2441 : 0 : j->action = *action;
2442 [ # # ]: 0 : TAILQ_INSERT_HEAD(&fm->jump_list, j, list);
2443 : 0 : ENICPMD_LOG(DEBUG, "saved jump flow: flow=%p group=%u", flow, group);
2444 : 0 : return 0;
2445 : : }
2446 : :
2447 : : static void
2448 : 0 : __enic_fm_flow_free(struct enic_flowman *fm, struct enic_fm_flow *fm_flow)
2449 : : {
2450 [ # # ]: 0 : if (fm_flow->entry_handle != FM_INVALID_HANDLE) {
2451 : 0 : enic_fm_entry_free(fm, fm_flow->entry_handle);
2452 : 0 : fm_flow->entry_handle = FM_INVALID_HANDLE;
2453 : : }
2454 [ # # ]: 0 : if (fm_flow->action != NULL) {
2455 : 0 : enic_fm_action_free(fm, fm_flow->action);
2456 : 0 : fm_flow->action = NULL;
2457 : : }
2458 : : enic_fm_counter_free(fm, fm_flow);
2459 [ # # ]: 0 : if (fm_flow->fet) {
2460 : 0 : enic_fet_put(fm, fm_flow->fet);
2461 : 0 : fm_flow->fet = NULL;
2462 : : }
2463 : 0 : }
2464 : :
2465 : : static void
2466 : 0 : enic_fm_flow_free(struct enic_flowman *fm, struct rte_flow *flow)
2467 : : {
2468 : 0 : struct enic_fm_flow *steer = flow->fm->hairpin_steer_flow;
2469 : :
2470 [ # # # # ]: 0 : if (flow->fm->fet && flow->fm->fet->default_key)
2471 : 0 : remove_jump_flow(fm, flow);
2472 : 0 : __enic_fm_flow_free(fm, flow->fm);
2473 [ # # ]: 0 : if (steer) {
2474 : 0 : __enic_fm_flow_free(fm, steer);
2475 : 0 : free(steer);
2476 : : }
2477 : 0 : free(flow->fm);
2478 : 0 : free(flow);
2479 : 0 : }
2480 : :
2481 : : static int
2482 : 0 : enic_fm_add_tcam_entry(struct enic_flowman *fm,
2483 : : struct fm_tcam_match_entry *match_in,
2484 : : uint64_t *entry_handle,
2485 : : uint8_t ingress,
2486 : : struct rte_flow_error *error)
2487 : : {
2488 : : struct fm_tcam_match_entry *ftm;
2489 : : uint64_t args[3];
2490 : : int ret;
2491 : :
2492 : 0 : ENICPMD_FUNC_TRACE();
2493 : : /* Copy entry to the command buffer */
2494 [ # # ]: 0 : ftm = &fm->cmd.va->fm_tcam_match_entry;
2495 : : memcpy(ftm, match_in, sizeof(*ftm));
2496 : : /* Add TCAM entry */
2497 : 0 : args[0] = FM_TCAM_ENTRY_INSTALL;
2498 [ # # ]: 0 : args[1] = ingress ? fm->ig_tcam_hndl : fm->eg_tcam_hndl;
2499 : 0 : args[2] = fm->cmd.pa;
2500 : : ret = flowman_cmd(fm, args, 3);
2501 [ # # ]: 0 : if (ret != 0) {
2502 [ # # ]: 0 : ENICPMD_LOG(ERR, "cannot add %s TCAM entry: rc=%d",
2503 : : ingress ? "ingress" : "egress", ret);
2504 : 0 : rte_flow_error_set(error, ret, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
2505 : : NULL, "enic: devcmd(tcam-entry-install)");
2506 : 0 : return ret;
2507 : : }
2508 [ # # ]: 0 : ENICPMD_LOG(DEBUG, "installed %s TCAM entry: handle=0x%" PRIx64,
2509 : : ingress ? "ingress" : "egress", (uint64_t)args[0]);
2510 : 0 : *entry_handle = args[0];
2511 : 0 : return 0;
2512 : : }
2513 : :
2514 : : static int
2515 : 0 : enic_fm_add_exact_entry(struct enic_flowman *fm,
2516 : : struct fm_tcam_match_entry *match_in,
2517 : : uint64_t *entry_handle,
2518 : : struct enic_fm_fet *fet,
2519 : : struct rte_flow_error *error)
2520 : : {
2521 : : struct fm_exact_match_entry *fem;
2522 : : uint64_t args[3];
2523 : : int ret;
2524 : :
2525 : 0 : ENICPMD_FUNC_TRACE();
2526 : : /* The new entry must have the table's key */
2527 [ # # ]: 0 : if (memcmp(fet->key.fk_hdrset, match_in->ftm_mask.fk_hdrset,
2528 : : sizeof(struct fm_header_set) * FM_HDRSET_MAX)) {
2529 : 0 : return rte_flow_error_set(error, EINVAL,
2530 : : RTE_FLOW_ERROR_TYPE_ITEM, NULL,
2531 : : "enic: key does not match group's key");
2532 : : }
2533 : :
2534 : : /* Copy entry to the command buffer */
2535 : 0 : fem = &fm->cmd.va->fm_exact_match_entry;
2536 : : /*
2537 : : * Translate TCAM entry to exact entry. As is only need to drop
2538 : : * position and mask. The mask is part of the exact match table.
2539 : : * Position (aka priority) is not supported in the exact match table.
2540 : : */
2541 : 0 : fem->fem_data = match_in->ftm_data;
2542 : 0 : fem->fem_flags = match_in->ftm_flags;
2543 : 0 : fem->fem_action = match_in->ftm_action;
2544 : 0 : fem->fem_counter = match_in->ftm_counter;
2545 : :
2546 : : /* Add exact entry */
2547 : 0 : args[0] = FM_EXACT_ENTRY_INSTALL;
2548 : 0 : args[1] = fet->handle;
2549 : 0 : args[2] = fm->cmd.pa;
2550 : : ret = flowman_cmd(fm, args, 3);
2551 [ # # ]: 0 : if (ret != 0) {
2552 [ # # ]: 0 : ENICPMD_LOG(ERR, "cannot add %s exact entry: group=%u",
2553 : : fet->ingress ? "ingress" : "egress", fet->group);
2554 : 0 : rte_flow_error_set(error, ret, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
2555 : : NULL, "enic: devcmd(exact-entry-install)");
2556 : 0 : return ret;
2557 : : }
2558 [ # # ]: 0 : ENICPMD_LOG(DEBUG, "installed %s exact entry: group=%u"
2559 : : " handle=0x%" PRIx64,
2560 : : fet->ingress ? "ingress" : "egress", fet->group,
2561 : : (uint64_t)args[0]);
2562 : 0 : *entry_handle = args[0];
2563 : 0 : return 0;
2564 : : }
2565 : :
2566 : : static int
2567 : 0 : enic_action_handle_get(struct enic_flowman *fm, struct fm_action *action_in,
2568 : : struct rte_flow_error *error,
2569 : : struct enic_fm_action **ah_o)
2570 : : {
2571 : : struct enic_fm_action *ah;
2572 : : struct fm_action *fma;
2573 : : uint64_t args[2];
2574 : : int ret = 0;
2575 : :
2576 : 0 : ret = rte_hash_lookup_data(fm->action_hash, action_in,
2577 : : (void **)&ah);
2578 [ # # ]: 0 : if (ret < 0 && ret != -ENOENT)
2579 : 0 : return rte_flow_error_set(error, -ret,
2580 : : RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
2581 : : NULL, "enic: rte_hash_lookup(action)");
2582 : :
2583 [ # # ]: 0 : if (ret == -ENOENT) {
2584 : : /* Allocate a new action on the NIC. */
2585 [ # # ]: 0 : fma = &fm->cmd.va->fm_action;
2586 : : memcpy(fma, action_in, sizeof(*fma));
2587 : :
2588 : 0 : ah = calloc(1, sizeof(*ah));
2589 [ # # ]: 0 : if (ah == NULL)
2590 : 0 : return rte_flow_error_set(error, ENOMEM,
2591 : : RTE_FLOW_ERROR_TYPE_HANDLE,
2592 : : NULL, "enic: calloc(fm-action)");
2593 : 0 : memcpy(&ah->key, action_in, sizeof(struct fm_action));
2594 : 0 : args[0] = FM_ACTION_ALLOC;
2595 : 0 : args[1] = fm->cmd.pa;
2596 : : ret = flowman_cmd(fm, args, 2);
2597 [ # # ]: 0 : if (ret != 0) {
2598 : 0 : rte_flow_error_set(error, -ret,
2599 : : RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
2600 : : NULL, "enic: devcmd(action-alloc)");
2601 : 0 : goto error_with_ah;
2602 : : }
2603 : 0 : ah->handle = args[0];
2604 : 0 : ret = rte_hash_add_key_data(fm->action_hash,
2605 : : (const void *)action_in,
2606 : : (void *)ah);
2607 [ # # ]: 0 : if (ret != 0) {
2608 : 0 : rte_flow_error_set(error, -ret,
2609 : : RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
2610 : : NULL,
2611 : : "enic: rte_hash_add_key_data(actn)");
2612 : 0 : goto error_with_action_handle;
2613 : : }
2614 : 0 : ENICPMD_LOG(DEBUG, "action allocated: handle=0x%" PRIx64,
2615 : : ah->handle);
2616 : : }
2617 : :
2618 : : /* Action handle struct is valid, increment reference count. */
2619 : 0 : ah->ref++;
2620 : 0 : *ah_o = ah;
2621 : 0 : return 0;
2622 : : error_with_action_handle:
2623 : 0 : args[0] = FM_ACTION_FREE;
2624 : 0 : args[1] = ah->handle;
2625 : : ret = flowman_cmd(fm, args, 2);
2626 [ # # ]: 0 : if (ret != 0)
2627 : 0 : rte_flow_error_set(error, -ret,
2628 : : RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
2629 : : NULL, "enic: devcmd(action-free)");
2630 : 0 : error_with_ah:
2631 : 0 : free(ah);
2632 : 0 : return ret;
2633 : : }
2634 : :
2635 : : /* Push match-action to the NIC. */
2636 : : static int
2637 : 0 : __enic_fm_flow_add_entry(struct enic_flowman *fm,
2638 : : struct enic_fm_flow *fm_flow,
2639 : : struct fm_tcam_match_entry *match_in,
2640 : : struct fm_action *action_in,
2641 : : uint32_t group,
2642 : : uint8_t ingress,
2643 : : struct rte_flow_error *error)
2644 : : {
2645 : : struct enic_fm_counter *ctr;
2646 : 0 : struct enic_fm_action *ah = NULL;
2647 : : uint64_t entry_h;
2648 : : int ret;
2649 : :
2650 : 0 : ENICPMD_FUNC_TRACE();
2651 : :
2652 : : /* Get or create an action handle. */
2653 : 0 : ret = enic_action_handle_get(fm, action_in, error, &ah);
2654 [ # # ]: 0 : if (ret)
2655 : : return ret;
2656 : 0 : match_in->ftm_action = ah->handle;
2657 : 0 : fm_flow->action = ah;
2658 : :
2659 : : /* Allocate counter if requested. */
2660 [ # # ]: 0 : if (match_in->ftm_flags & FMEF_COUNTER) {
2661 : 0 : ret = enic_fm_counter_alloc(fm, error, &ctr);
2662 [ # # ]: 0 : if (ret) /* error has been filled in */
2663 : : return ret;
2664 : 0 : fm_flow->counter_valid = true;
2665 : 0 : fm_flow->counter = ctr;
2666 : 0 : match_in->ftm_counter = ctr->handle;
2667 : : }
2668 : :
2669 : : /*
2670 : : * Get the group's table (either TCAM or exact match table) and
2671 : : * add entry to it. If we use the exact match table, the handler
2672 : : * will translate the TCAM entry (match_in) to the appropriate
2673 : : * exact match entry and use that instead.
2674 : : */
2675 : 0 : entry_h = FM_INVALID_HANDLE;
2676 [ # # ]: 0 : if (group == FM_TCAM_RTE_GROUP) {
2677 : 0 : ret = enic_fm_add_tcam_entry(fm, match_in, &entry_h, ingress,
2678 : : error);
2679 [ # # ]: 0 : if (ret)
2680 : : return ret;
2681 : : /* Jump action might have a ref to fet */
2682 : 0 : fm_flow->fet = fm->fet;
2683 : 0 : fm->fet = NULL;
2684 : : } else {
2685 : 0 : struct enic_fm_fet *fet = NULL;
2686 : :
2687 : 0 : ret = enic_fet_get(fm, group, ingress,
2688 : : &match_in->ftm_mask, &fet, error);
2689 [ # # ]: 0 : if (ret)
2690 : 0 : return ret;
2691 : 0 : fm_flow->fet = fet;
2692 : 0 : ret = enic_fm_add_exact_entry(fm, match_in, &entry_h, fet,
2693 : : error);
2694 [ # # ]: 0 : if (ret)
2695 : : return ret;
2696 : : }
2697 : : /* Clear counter after adding entry, as it requires in-use counter */
2698 [ # # ]: 0 : if (fm_flow->counter_valid) {
2699 : 0 : ret = enic_fm_counter_zero(fm, fm_flow->counter);
2700 [ # # ]: 0 : if (ret)
2701 : : return ret;
2702 : : }
2703 : 0 : fm_flow->entry_handle = entry_h;
2704 : 0 : return 0;
2705 : : }
2706 : :
2707 : : /* Push match-action to the NIC. */
2708 : : static struct rte_flow *
2709 : 0 : enic_fm_flow_add_entry(struct enic_flowman *fm,
2710 : : struct fm_tcam_match_entry *match_in,
2711 : : struct fm_action *action_in,
2712 : : const struct rte_flow_attr *attrs,
2713 : : struct rte_flow_error *error)
2714 : : {
2715 : : struct enic_fm_flow *fm_flow;
2716 : : struct rte_flow *flow;
2717 : :
2718 : 0 : ENICPMD_FUNC_TRACE();
2719 : 0 : match_in->ftm_position = attrs->priority;
2720 : 0 : enic_fm_dump_tcam_entry(match_in, action_in, attrs->ingress);
2721 : 0 : flow = calloc(1, sizeof(*flow));
2722 : 0 : fm_flow = calloc(1, sizeof(*fm_flow));
2723 [ # # ]: 0 : if (flow == NULL || fm_flow == NULL) {
2724 : 0 : rte_flow_error_set(error, ENOMEM, RTE_FLOW_ERROR_TYPE_HANDLE,
2725 : : NULL, "enic: cannot allocate rte_flow");
2726 : 0 : free(flow);
2727 : 0 : free(fm_flow);
2728 : 0 : return NULL;
2729 : : }
2730 : 0 : flow->fm = fm_flow;
2731 : 0 : fm_flow->action = NULL;
2732 : 0 : fm_flow->entry_handle = FM_INVALID_HANDLE;
2733 [ # # ]: 0 : if (__enic_fm_flow_add_entry(fm, fm_flow, match_in, action_in,
2734 : 0 : attrs->group, attrs->ingress, error)) {
2735 : 0 : enic_fm_flow_free(fm, flow);
2736 : 0 : return NULL;
2737 : : }
2738 : : return flow;
2739 : : }
2740 : :
2741 : : static void
2742 : 0 : convert_jump_flows(struct enic_flowman *fm, struct enic_fm_fet *fet,
2743 : : struct rte_flow_error *error)
2744 : : {
2745 : : struct enic_fm_flow *fm_flow;
2746 : : struct enic_fm_jump_flow *j;
2747 : : struct fm_action *fma;
2748 : : uint32_t group;
2749 : :
2750 : 0 : ENICPMD_FUNC_TRACE();
2751 : : /*
2752 : : * Find the saved flows that should jump to the new table (fet).
2753 : : * Then delete the old TCAM entry that jumps to the default table,
2754 : : * and add a new one that jumps to the new table.
2755 : : */
2756 : 0 : group = fet->group;
2757 : 0 : j = find_jump_flow(fm, group);
2758 [ # # ]: 0 : while (j) {
2759 : 0 : ENICPMD_LOG(DEBUG, "convert jump flow: flow=%p group=%u",
2760 : : j->flow, group);
2761 : : /* Delete old entry */
2762 : 0 : fm_flow = j->flow->fm;
2763 : 0 : __enic_fm_flow_free(fm, fm_flow);
2764 : :
2765 : : /* Add new entry */
2766 : 0 : fma = &j->action;
2767 : 0 : fma->fma_action_ops[0].exact.handle = fet->handle;
2768 [ # # ]: 0 : if (__enic_fm_flow_add_entry(fm, fm_flow, &j->match, fma,
2769 : 0 : FM_TCAM_RTE_GROUP, fet->ingress, error)) {
2770 : : /* Cannot roll back changes at the moment */
2771 : 0 : ENICPMD_LOG(ERR, "cannot convert jump flow: flow=%p",
2772 : : j->flow);
2773 : : } else {
2774 : 0 : fm_flow->fet = fet;
2775 : 0 : fet->ref++;
2776 : 0 : ENICPMD_LOG(DEBUG, "convert ok: group=%u ref=%u",
2777 : : fet->group, fet->ref);
2778 : : }
2779 : :
2780 [ # # ]: 0 : TAILQ_REMOVE(&fm->jump_list, j, list);
2781 : 0 : free(j);
2782 : 0 : j = find_jump_flow(fm, group);
2783 : : }
2784 : 0 : }
2785 : :
2786 : : static int
2787 : 0 : add_hairpin_steer(struct enic_flowman *fm, struct rte_flow *flow,
2788 : : struct rte_flow_error *error)
2789 : : {
2790 : : struct fm_tcam_match_entry *fm_tcam_entry;
2791 : : struct enic_fm_flow *fm_flow;
2792 : : struct fm_action *fm_action;
2793 : : struct fm_action_op fm_op;
2794 : : int ret;
2795 : :
2796 : 0 : ENICPMD_FUNC_TRACE();
2797 : 0 : fm_flow = calloc(1, sizeof(*fm_flow));
2798 [ # # ]: 0 : if (fm_flow == NULL) {
2799 : 0 : rte_flow_error_set(error, ENOMEM, RTE_FLOW_ERROR_TYPE_HANDLE,
2800 : : NULL, "enic: cannot allocate rte_flow");
2801 : 0 : return -ENOMEM;
2802 : : }
2803 : : /* Original egress hairpin flow */
2804 : 0 : fm_tcam_entry = &fm->tcam_entry;
2805 : 0 : fm_action = &fm->action;
2806 : : /* Use the match pattern of the egress flow as is, without counters */
2807 : 0 : fm_tcam_entry->ftm_flags &= ~FMEF_COUNTER;
2808 : : /* The only action is steer to vnic */
2809 : 0 : fm->action_op_count = 0;
2810 : : memset(fm_action, 0, sizeof(*fm_action));
2811 : : memset(&fm_op, 0, sizeof(fm_op));
2812 : : /* Always to queue 0 for now */
2813 : 0 : fm_op.fa_op = FMOP_RQ_STEER;
2814 : : fm_op.rq_steer.rq_index = 0;
2815 : 0 : fm_op.rq_steer.vnic_handle = fm->hairpin_steer_vnic_h;
2816 : 0 : ret = enic_fm_append_action_op(fm, &fm_op, error);
2817 [ # # ]: 0 : if (ret)
2818 : 0 : goto error_with_flow;
2819 : 0 : ENICPMD_LOG(DEBUG, "add steer op");
2820 : : /* Add required END */
2821 : : memset(&fm_op, 0, sizeof(fm_op));
2822 : 0 : fm_op.fa_op = FMOP_END;
2823 : 0 : ret = enic_fm_append_action_op(fm, &fm_op, error);
2824 [ # # ]: 0 : if (ret)
2825 : 0 : goto error_with_flow;
2826 : : /* Add the ingress flow */
2827 : 0 : fm_flow->action = NULL;
2828 : 0 : fm_flow->entry_handle = FM_INVALID_HANDLE;
2829 : 0 : ret = __enic_fm_flow_add_entry(fm, fm_flow, fm_tcam_entry, fm_action,
2830 : : FM_TCAM_RTE_GROUP, 1 /* ingress */, error);
2831 [ # # ]: 0 : if (ret) {
2832 : 0 : ENICPMD_LOG(ERR, "cannot add hairpin-steer flow");
2833 : 0 : goto error_with_flow;
2834 : : }
2835 : : /* The new flow is now the egress flow's paired flow */
2836 : 0 : flow->fm->hairpin_steer_flow = fm_flow;
2837 : 0 : return 0;
2838 : :
2839 : 0 : error_with_flow:
2840 : 0 : free(fm_flow);
2841 : 0 : return ret;
2842 : : }
2843 : :
2844 : : static void
2845 : 0 : enic_fm_open_scratch(struct enic_flowman *fm)
2846 : : {
2847 : 0 : fm->action_op_count = 0;
2848 : 0 : fm->fet = NULL;
2849 : 0 : fm->need_hairpin_steer = 0;
2850 : 0 : fm->hairpin_steer_vnic_h = 0;
2851 : 0 : memset(&fm->tcam_entry, 0, sizeof(fm->tcam_entry));
2852 : 0 : memset(&fm->action, 0, sizeof(fm->action));
2853 : 0 : }
2854 : :
2855 : : static void
2856 : : enic_fm_close_scratch(struct enic_flowman *fm)
2857 : : {
2858 [ # # # # : 0 : if (fm->fet) {
# # # # #
# ]
2859 : 0 : enic_fet_put(fm, fm->fet);
2860 : 0 : fm->fet = NULL;
2861 : : }
2862 : 0 : fm->action_op_count = 0;
2863 : : }
2864 : :
2865 : : static int
2866 : 0 : enic_fm_flow_validate(struct rte_eth_dev *dev,
2867 : : const struct rte_flow_attr *attrs,
2868 : : const struct rte_flow_item pattern[],
2869 : : const struct rte_flow_action actions[],
2870 : : struct rte_flow_error *error)
2871 : : {
2872 : : struct fm_tcam_match_entry *fm_tcam_entry;
2873 : : struct fm_action *fm_action;
2874 : : struct enic_flowman *fm;
2875 : : int ret;
2876 : :
2877 : 0 : ENICPMD_FUNC_TRACE();
2878 : 0 : fm = begin_fm(pmd_priv(dev));
2879 [ # # ]: 0 : if (fm == NULL)
2880 : : return -ENOTSUP;
2881 : 0 : enic_fm_open_scratch(fm);
2882 : 0 : ret = enic_fm_flow_parse(fm, attrs, pattern, actions, error);
2883 [ # # ]: 0 : if (!ret) {
2884 : 0 : fm_tcam_entry = &fm->tcam_entry;
2885 : 0 : fm_action = &fm->action;
2886 : 0 : enic_fm_dump_tcam_entry(fm_tcam_entry, fm_action,
2887 : 0 : attrs->ingress);
2888 : : }
2889 : : enic_fm_close_scratch(fm);
2890 : : end_fm(fm);
2891 : : return ret;
2892 : : }
2893 : :
2894 : : static int
2895 : 0 : enic_fm_flow_query_count(struct rte_eth_dev *dev,
2896 : : struct rte_flow *flow, void *data,
2897 : : struct rte_flow_error *error)
2898 : : {
2899 : : struct rte_flow_query_count *query;
2900 : : struct enic_fm_flow *fm_flow;
2901 : : struct enic_flowman *fm;
2902 : : uint64_t args[3];
2903 : : int rc;
2904 : :
2905 : 0 : ENICPMD_FUNC_TRACE();
2906 : 0 : fm = begin_fm(pmd_priv(dev));
2907 : : query = data;
2908 : 0 : fm_flow = flow->fm;
2909 [ # # ]: 0 : if (!fm_flow->counter_valid) {
2910 : 0 : rc = rte_flow_error_set(error, ENOTSUP,
2911 : : RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
2912 : : "enic: flow does not have counter");
2913 : 0 : goto exit;
2914 : : }
2915 : :
2916 : 0 : args[0] = FM_COUNTER_QUERY;
2917 : 0 : args[1] = fm_flow->counter->handle;
2918 : 0 : args[2] = query->reset;
2919 : : rc = flowman_cmd(fm, args, 3);
2920 [ # # ]: 0 : if (rc) {
2921 : 0 : ENICPMD_LOG(ERR, "cannot query counter: rc=%d handle=0x%x",
2922 : : rc, fm_flow->counter->handle);
2923 : 0 : goto exit;
2924 : : }
2925 : 0 : query->hits_set = 1;
2926 : 0 : query->hits = args[0];
2927 : 0 : query->bytes_set = 1;
2928 : 0 : query->bytes = args[1];
2929 : : rc = 0;
2930 : 0 : exit:
2931 : : end_fm(fm);
2932 : 0 : return rc;
2933 : : }
2934 : :
2935 : : static int
2936 : 0 : enic_fm_flow_query(struct rte_eth_dev *dev,
2937 : : struct rte_flow *flow,
2938 : : const struct rte_flow_action *actions,
2939 : : void *data,
2940 : : struct rte_flow_error *error)
2941 : : {
2942 : : int ret = 0;
2943 : :
2944 : 0 : ENICPMD_FUNC_TRACE();
2945 [ # # ]: 0 : for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) {
2946 [ # # # ]: 0 : switch (actions->type) {
2947 : : case RTE_FLOW_ACTION_TYPE_VOID:
2948 : : break;
2949 : 0 : case RTE_FLOW_ACTION_TYPE_COUNT:
2950 : 0 : ret = enic_fm_flow_query_count(dev, flow, data, error);
2951 : 0 : break;
2952 : 0 : default:
2953 : 0 : return rte_flow_error_set(error, ENOTSUP,
2954 : : RTE_FLOW_ERROR_TYPE_ACTION,
2955 : : actions,
2956 : : "action not supported");
2957 : : }
2958 [ # # ]: 0 : if (ret < 0)
2959 : 0 : return ret;
2960 : : }
2961 : : return 0;
2962 : : }
2963 : :
2964 : : static struct rte_flow *
2965 : 0 : enic_fm_flow_create(struct rte_eth_dev *dev,
2966 : : const struct rte_flow_attr *attrs,
2967 : : const struct rte_flow_item pattern[],
2968 : : const struct rte_flow_action actions[],
2969 : : struct rte_flow_error *error)
2970 : : {
2971 : : struct fm_tcam_match_entry *fm_tcam_entry;
2972 : : struct fm_action *fm_action;
2973 : : struct enic_flowman *fm;
2974 : : struct enic_fm_fet *fet;
2975 : : struct rte_flow *flow;
2976 : : struct enic *enic;
2977 : : int ret;
2978 : :
2979 : 0 : ENICPMD_FUNC_TRACE();
2980 : : enic = pmd_priv(dev);
2981 : 0 : fm = begin_fm(enic);
2982 [ # # ]: 0 : if (fm == NULL) {
2983 : 0 : rte_flow_error_set(error, ENOTSUP,
2984 : : RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
2985 : : "flowman is not initialized");
2986 : 0 : return NULL;
2987 : : }
2988 : 0 : enic_fm_open_scratch(fm);
2989 : : flow = NULL;
2990 : 0 : ret = enic_fm_flow_parse(fm, attrs, pattern, actions, error);
2991 [ # # ]: 0 : if (ret < 0)
2992 : 0 : goto error_with_scratch;
2993 : 0 : fm_tcam_entry = &fm->tcam_entry;
2994 : 0 : fm_action = &fm->action;
2995 : 0 : flow = enic_fm_flow_add_entry(fm, fm_tcam_entry, fm_action,
2996 : : attrs, error);
2997 [ # # ]: 0 : if (flow) {
2998 : : /* Add ingress rule that pairs with hairpin rule */
2999 [ # # ]: 0 : if (fm->need_hairpin_steer) {
3000 : 0 : ret = add_hairpin_steer(fm, flow, error);
3001 [ # # ]: 0 : if (ret) {
3002 : 0 : enic_fm_flow_free(fm, flow);
3003 : : flow = NULL;
3004 : 0 : goto error_with_scratch;
3005 : : }
3006 : : }
3007 [ # # ]: 0 : LIST_INSERT_HEAD(&enic->flows, flow, next);
3008 : 0 : fet = flow->fm->fet;
3009 [ # # # # ]: 0 : if (fet && fet->default_key) {
3010 : : /*
3011 : : * Jump to non-existent group? Save the relevant info
3012 : : * so we can convert this flow when that group
3013 : : * materializes.
3014 : : */
3015 : 0 : save_jump_flow(fm, flow, fet->group,
3016 : : fm_tcam_entry, fm_action);
3017 [ # # # # ]: 0 : } else if (fet && fet->ref == 1) {
3018 : : /*
3019 : : * A new table is created. Convert the saved flows
3020 : : * that should jump to this group.
3021 : : */
3022 : 0 : convert_jump_flows(fm, fet, error);
3023 : : }
3024 : : }
3025 : :
3026 [ # # ]: 0 : error_with_scratch:
3027 : : enic_fm_close_scratch(fm);
3028 : : end_fm(fm);
3029 : : return flow;
3030 : : }
3031 : :
3032 : : static int
3033 : 0 : enic_fm_flow_destroy(struct rte_eth_dev *dev, struct rte_flow *flow,
3034 : : __rte_unused struct rte_flow_error *error)
3035 : : {
3036 : : struct enic *enic = pmd_priv(dev);
3037 : : struct enic_flowman *fm;
3038 : :
3039 : 0 : ENICPMD_FUNC_TRACE();
3040 : 0 : fm = begin_fm(enic);
3041 [ # # ]: 0 : if (fm == NULL)
3042 : : return 0;
3043 [ # # ]: 0 : LIST_REMOVE(flow, next);
3044 : 0 : enic_fm_flow_free(fm, flow);
3045 : : end_fm(fm);
3046 : : return 0;
3047 : : }
3048 : :
3049 : : static int
3050 : 0 : enic_fm_flow_flush(struct rte_eth_dev *dev,
3051 : : __rte_unused struct rte_flow_error *error)
3052 : : {
3053 : : LIST_HEAD(enic_flows, rte_flow) internal;
3054 : : struct enic_fm_flow *fm_flow;
3055 : : struct enic_flowman *fm;
3056 : : struct rte_flow *flow;
3057 : : struct enic *enic = pmd_priv(dev);
3058 : :
3059 : 0 : ENICPMD_FUNC_TRACE();
3060 : :
3061 : 0 : fm = begin_fm(enic);
3062 [ # # ]: 0 : if (fm == NULL)
3063 : : return 0;
3064 : : /* Destroy all non-internal flows */
3065 : 0 : LIST_INIT(&internal);
3066 [ # # ]: 0 : while (!LIST_EMPTY(&enic->flows)) {
3067 : : flow = LIST_FIRST(&enic->flows);
3068 : 0 : fm_flow = flow->fm;
3069 [ # # ]: 0 : LIST_REMOVE(flow, next);
3070 [ # # ]: 0 : if (flow->internal) {
3071 [ # # ]: 0 : LIST_INSERT_HEAD(&internal, flow, next);
3072 : 0 : continue;
3073 : : }
3074 : : /*
3075 : : * If tables are null, then vNIC is closing, and the firmware
3076 : : * has already cleaned up flowman state. So do not try to free
3077 : : * resources, as it only causes errors.
3078 : : */
3079 [ # # ]: 0 : if (fm->ig_tcam_hndl == FM_INVALID_HANDLE) {
3080 : 0 : fm_flow->entry_handle = FM_INVALID_HANDLE;
3081 : 0 : fm_flow->action = NULL;
3082 : 0 : fm_flow->fet = NULL;
3083 : : }
3084 : 0 : enic_fm_flow_free(fm, flow);
3085 : : }
3086 [ # # ]: 0 : while (!LIST_EMPTY(&internal)) {
3087 : : flow = LIST_FIRST(&internal);
3088 [ # # ]: 0 : LIST_REMOVE(flow, next);
3089 [ # # ]: 0 : LIST_INSERT_HEAD(&enic->flows, flow, next);
3090 : : }
3091 : : end_fm(fm);
3092 : : return 0;
3093 : : }
3094 : :
3095 : : static int
3096 : 0 : enic_fm_tbl_free(struct enic_flowman *fm, uint64_t handle)
3097 : : {
3098 : : uint64_t args[2];
3099 : : int rc;
3100 : :
3101 : 0 : args[0] = FM_MATCH_TABLE_FREE;
3102 : 0 : args[1] = handle;
3103 : : rc = flowman_cmd(fm, args, 2);
3104 [ # # ]: 0 : if (rc)
3105 : 0 : ENICPMD_LOG(ERR, "cannot free table: rc=%d handle=0x%" PRIx64,
3106 : : rc, handle);
3107 : 0 : return rc;
3108 : : }
3109 : :
3110 : : static int
3111 : 0 : enic_fm_tcam_tbl_alloc(struct enic_flowman *fm, uint32_t direction,
3112 : : uint32_t max_entries, uint64_t *handle)
3113 : : {
3114 : : struct fm_tcam_match_table *tcam_tbl;
3115 : : uint64_t args[2];
3116 : : int rc;
3117 : :
3118 : 0 : ENICPMD_FUNC_TRACE();
3119 : 0 : tcam_tbl = &fm->cmd.va->fm_tcam_match_table;
3120 : 0 : tcam_tbl->ftt_direction = direction;
3121 : 0 : tcam_tbl->ftt_stage = FM_STAGE_LAST;
3122 : 0 : tcam_tbl->ftt_max_entries = max_entries;
3123 : 0 : args[0] = FM_TCAM_TABLE_ALLOC;
3124 : 0 : args[1] = fm->cmd.pa;
3125 : : rc = flowman_cmd(fm, args, 2);
3126 [ # # ]: 0 : if (rc) {
3127 [ # # ]: 0 : ENICPMD_LOG(ERR, "cannot alloc %s TCAM table: rc=%d",
3128 : : (direction == FM_INGRESS) ? "IG" : "EG", rc);
3129 : 0 : return rc;
3130 : : }
3131 : 0 : *handle = args[0];
3132 [ # # ]: 0 : ENICPMD_LOG(DEBUG, "%s TCAM table allocated, handle=0x%" PRIx64,
3133 : : (direction == FM_INGRESS) ? "IG" : "EG", *handle);
3134 : 0 : return 0;
3135 : : }
3136 : :
3137 : : static int
3138 : 0 : enic_fm_init_actions(struct enic_flowman *fm)
3139 : : {
3140 : : struct rte_hash *a_hash;
3141 : : char name[RTE_HASH_NAMESIZE];
3142 : 0 : struct rte_hash_parameters params = {
3143 : : .entries = FM_MAX_ACTION_TABLE_SIZE,
3144 : : .key_len = sizeof(struct fm_action),
3145 : : .hash_func = rte_jhash,
3146 : : .hash_func_init_val = 0,
3147 : 0 : .socket_id = rte_socket_id(),
3148 : : };
3149 : :
3150 : 0 : ENICPMD_FUNC_TRACE();
3151 : : snprintf((char *)name, sizeof(name), "fm-ah-%s",
3152 : 0 : fm->owner_enic->bdf_name);
3153 : 0 : params.name = name;
3154 : :
3155 : 0 : a_hash = rte_hash_create(¶ms);
3156 [ # # ]: 0 : if (a_hash == NULL)
3157 : 0 : return -rte_errno;
3158 : 0 : fm->action_hash = a_hash;
3159 : 0 : return 0;
3160 : : }
3161 : :
3162 : : static int
3163 : 0 : enic_fm_init_counters(struct enic_flowman *fm)
3164 : : {
3165 : 0 : ENICPMD_FUNC_TRACE();
3166 : 0 : SLIST_INIT(&fm->counters);
3167 : 0 : return enic_fm_more_counters(fm);
3168 : : }
3169 : :
3170 : : static void
3171 : 0 : enic_fm_free_all_counters(struct enic_flowman *fm)
3172 : : {
3173 : : uint64_t args[2];
3174 : : int rc;
3175 : :
3176 : 0 : args[0] = FM_COUNTER_BRK;
3177 : 0 : args[1] = 0;
3178 : : rc = flowman_cmd(fm, args, 2);
3179 [ # # ]: 0 : if (rc != 0)
3180 : 0 : ENICPMD_LOG(ERR, "cannot free counters: rc=%d", rc);
3181 : 0 : rte_free(fm->counter_stack);
3182 : 0 : }
3183 : :
3184 : : static int
3185 : 0 : enic_fm_alloc_tcam_tables(struct enic_flowman *fm)
3186 : : {
3187 : : int rc;
3188 : :
3189 : 0 : ENICPMD_FUNC_TRACE();
3190 : 0 : rc = enic_fm_tcam_tbl_alloc(fm, FM_INGRESS, FM_MAX_TCAM_TABLE_SIZE,
3191 : : &fm->ig_tcam_hndl);
3192 [ # # ]: 0 : if (rc)
3193 : : return rc;
3194 : 0 : rc = enic_fm_tcam_tbl_alloc(fm, FM_EGRESS, FM_MAX_TCAM_TABLE_SIZE,
3195 : : &fm->eg_tcam_hndl);
3196 : 0 : return rc;
3197 : : }
3198 : :
3199 : : static void
3200 : 0 : enic_fm_free_tcam_tables(struct enic_flowman *fm)
3201 : : {
3202 : 0 : ENICPMD_FUNC_TRACE();
3203 [ # # ]: 0 : if (fm->ig_tcam_hndl) {
3204 : 0 : ENICPMD_LOG(DEBUG, "free IG TCAM table handle=0x%" PRIx64,
3205 : : fm->ig_tcam_hndl);
3206 : 0 : enic_fm_tbl_free(fm, fm->ig_tcam_hndl);
3207 : 0 : fm->ig_tcam_hndl = FM_INVALID_HANDLE;
3208 : : }
3209 [ # # ]: 0 : if (fm->eg_tcam_hndl) {
3210 : 0 : ENICPMD_LOG(DEBUG, "free EG TCAM table handle=0x%" PRIx64,
3211 : : fm->eg_tcam_hndl);
3212 : 0 : enic_fm_tbl_free(fm, fm->eg_tcam_hndl);
3213 : 0 : fm->eg_tcam_hndl = FM_INVALID_HANDLE;
3214 : : }
3215 : 0 : }
3216 : :
3217 : : int
3218 : 0 : enic_fm_init(struct enic *enic)
3219 : : {
3220 : : const struct rte_pci_addr *addr;
3221 : : struct enic_flowman *fm;
3222 : : uint8_t name[RTE_MEMZONE_NAMESIZE];
3223 : : int rc;
3224 : :
3225 [ # # ]: 0 : if (enic->flow_filter_mode != FILTER_FLOWMAN)
3226 : : return 0;
3227 : 0 : ENICPMD_FUNC_TRACE();
3228 : : /* Get vnic handle and save for port-id action */
3229 [ # # ]: 0 : if (rte_eth_dev_is_repr(enic->rte_dev))
3230 : 0 : addr = &VF_ENIC_TO_VF_REP(enic)->bdf;
3231 : : else
3232 : 0 : addr = &RTE_ETH_DEV_TO_PCI(enic->rte_dev)->addr;
3233 : 0 : rc = enic_fm_find_vnic(enic, addr, &enic->fm_vnic_handle);
3234 [ # # ]: 0 : if (rc) {
3235 : 0 : ENICPMD_LOG(ERR, "cannot find vnic handle for %x:%x:%x",
3236 : : addr->bus, addr->devid, addr->function);
3237 : 0 : return rc;
3238 : : }
3239 : : /* Save UIF for egport action */
3240 : 0 : enic->fm_vnic_uif = vnic_dev_uif(enic->vdev);
3241 : 0 : ENICPMD_LOG(DEBUG, "uif %u", enic->fm_vnic_uif);
3242 : : /* Nothing else to do for representor. It will share the PF flowman */
3243 [ # # ]: 0 : if (rte_eth_dev_is_repr(enic->rte_dev))
3244 : : return 0;
3245 : 0 : fm = calloc(1, sizeof(*fm));
3246 [ # # ]: 0 : if (fm == NULL) {
3247 : 0 : ENICPMD_LOG(ERR, "cannot alloc flowman struct");
3248 : 0 : return -ENOMEM;
3249 : : }
3250 : 0 : fm->owner_enic = enic;
3251 : : rte_spinlock_init(&fm->lock);
3252 : 0 : TAILQ_INIT(&fm->fet_list);
3253 : 0 : TAILQ_INIT(&fm->jump_list);
3254 : : /* Allocate host memory for flowman commands */
3255 : 0 : snprintf((char *)name, sizeof(name), "fm-cmd-%s", enic->bdf_name);
3256 : 0 : fm->cmd.va = enic_alloc_consistent(enic,
3257 : : sizeof(union enic_flowman_cmd_mem), &fm->cmd.pa, name);
3258 [ # # ]: 0 : if (!fm->cmd.va) {
3259 : 0 : ENICPMD_LOG(ERR, "cannot allocate flowman command memory");
3260 : : rc = -ENOMEM;
3261 : 0 : goto error_fm;
3262 : : }
3263 : : /* Allocate TCAM tables upfront as they are the main tables */
3264 : 0 : rc = enic_fm_alloc_tcam_tables(fm);
3265 [ # # ]: 0 : if (rc) {
3266 : 0 : ENICPMD_LOG(ERR, "cannot alloc TCAM tables");
3267 : 0 : goto error_cmd;
3268 : : }
3269 : : /* Then a number of counters */
3270 : 0 : rc = enic_fm_init_counters(fm);
3271 [ # # ]: 0 : if (rc) {
3272 : 0 : ENICPMD_LOG(ERR, "cannot alloc counters");
3273 : 0 : goto error_tables;
3274 : : }
3275 : : /* set up action handle hash */
3276 : 0 : rc = enic_fm_init_actions(fm);
3277 [ # # ]: 0 : if (rc) {
3278 : 0 : ENICPMD_LOG(ERR, "cannot create action hash, error:%d", rc);
3279 : 0 : goto error_counters;
3280 : : }
3281 : : /*
3282 : : * One default exact match table for each direction. We hold onto
3283 : : * it until close.
3284 : : */
3285 : 0 : rc = enic_fet_alloc(fm, 1, NULL, 128, &fm->default_ig_fet);
3286 [ # # ]: 0 : if (rc) {
3287 : 0 : ENICPMD_LOG(ERR, "cannot alloc default IG exact match table");
3288 : 0 : goto error_actions;
3289 : : }
3290 : 0 : fm->default_ig_fet->ref = 1;
3291 : 0 : rc = enic_fet_alloc(fm, 0, NULL, 128, &fm->default_eg_fet);
3292 [ # # ]: 0 : if (rc) {
3293 : 0 : ENICPMD_LOG(ERR, "cannot alloc default EG exact match table");
3294 : 0 : goto error_ig_fet;
3295 : : }
3296 : 0 : fm->default_eg_fet->ref = 1;
3297 : 0 : fm->vf_rep_tag = FM_VF_REP_TAG;
3298 : 0 : enic->fm = fm;
3299 : 0 : return 0;
3300 : :
3301 : : error_ig_fet:
3302 : 0 : enic_fet_free(fm, fm->default_ig_fet);
3303 : 0 : error_actions:
3304 : 0 : rte_hash_free(fm->action_hash);
3305 : 0 : error_counters:
3306 : 0 : enic_fm_free_all_counters(fm);
3307 : 0 : error_tables:
3308 : 0 : enic_fm_free_tcam_tables(fm);
3309 : 0 : error_cmd:
3310 : 0 : enic_free_consistent(enic, sizeof(union enic_flowman_cmd_mem),
3311 : 0 : fm->cmd.va, fm->cmd.pa);
3312 : 0 : error_fm:
3313 : 0 : free(fm);
3314 : 0 : return rc;
3315 : : }
3316 : :
3317 : : void
3318 : 0 : enic_fm_destroy(struct enic *enic)
3319 : : {
3320 : : struct enic_flowman *fm;
3321 : : struct enic_fm_fet *fet;
3322 : :
3323 : 0 : ENICPMD_FUNC_TRACE();
3324 [ # # ]: 0 : if (rte_eth_dev_is_repr(enic->rte_dev)) {
3325 : 0 : delete_rep_flows(enic);
3326 : 0 : return;
3327 : : }
3328 [ # # ]: 0 : if (enic->fm == NULL)
3329 : : return;
3330 : : fm = enic->fm;
3331 : 0 : enic_fm_flow_flush(enic->rte_dev, NULL);
3332 : 0 : enic_fet_free(fm, fm->default_eg_fet);
3333 : 0 : enic_fet_free(fm, fm->default_ig_fet);
3334 : : /* Free all exact match tables still open */
3335 [ # # ]: 0 : while (!TAILQ_EMPTY(&fm->fet_list)) {
3336 : : fet = TAILQ_FIRST(&fm->fet_list);
3337 : 0 : enic_fet_free(fm, fet);
3338 : : }
3339 : 0 : enic_fm_free_tcam_tables(fm);
3340 : 0 : enic_fm_free_all_counters(fm);
3341 : 0 : rte_hash_free(fm->action_hash);
3342 : 0 : enic_free_consistent(enic, sizeof(union enic_flowman_cmd_mem),
3343 : 0 : fm->cmd.va, fm->cmd.pa);
3344 : : fm->cmd.va = NULL;
3345 : 0 : free(fm);
3346 : 0 : enic->fm = NULL;
3347 : : }
3348 : :
3349 : : int
3350 : 0 : enic_fm_allocate_switch_domain(struct enic *pf)
3351 : : {
3352 : : const struct rte_pci_addr *cur_a, *prev_a;
3353 : : struct rte_eth_dev *dev;
3354 : : struct enic *cur, *prev;
3355 : : uint16_t domain_id;
3356 : : uint64_t vnic_h;
3357 : : uint16_t pid;
3358 : : int ret;
3359 : :
3360 : 0 : ENICPMD_FUNC_TRACE();
3361 [ # # ]: 0 : if (rte_eth_dev_is_repr(pf->rte_dev))
3362 : : return -EINVAL;
3363 : : cur = pf;
3364 : 0 : cur_a = &RTE_ETH_DEV_TO_PCI(cur->rte_dev)->addr;
3365 : : /* Go through ports and find another PF that is on the same adapter */
3366 [ # # ]: 0 : RTE_ETH_FOREACH_DEV(pid) {
3367 : 0 : dev = &rte_eth_devices[pid];
3368 [ # # ]: 0 : if (!dev_is_enic(dev))
3369 : 0 : continue;
3370 [ # # ]: 0 : if (rte_eth_dev_is_repr(dev))
3371 : 0 : continue;
3372 [ # # ]: 0 : if (dev == cur->rte_dev)
3373 : 0 : continue;
3374 : : /* dev is another PF. Is it on the same adapter? */
3375 : : prev = pmd_priv(dev);
3376 : 0 : prev_a = &RTE_ETH_DEV_TO_PCI(dev)->addr;
3377 [ # # ]: 0 : if (!enic_fm_find_vnic(cur, prev_a, &vnic_h)) {
3378 : 0 : ENICPMD_LOG(DEBUG, "Port %u (PF BDF %x:%x:%x) and port %u (PF BDF %x:%x:%x domain %u) are on the same VIC",
3379 : : cur->rte_dev->data->port_id,
3380 : : cur_a->bus, cur_a->devid, cur_a->function,
3381 : : dev->data->port_id,
3382 : : prev_a->bus, prev_a->devid, prev_a->function,
3383 : : prev->switch_domain_id);
3384 : 0 : cur->switch_domain_id = prev->switch_domain_id;
3385 : 0 : return 0;
3386 : : }
3387 : : }
3388 : 0 : ret = rte_eth_switch_domain_alloc(&domain_id);
3389 [ # # ]: 0 : if (ret) {
3390 : 0 : ENICPMD_LOG(WARNING, "failed to allocate switch domain for device %d",
3391 : : ret);
3392 : : }
3393 : 0 : cur->switch_domain_id = domain_id;
3394 : 0 : ENICPMD_LOG(DEBUG, "Port %u (PF BDF %x:%x:%x) is the 1st PF on the VIC. Allocated switch domain id %u",
3395 : : cur->rte_dev->data->port_id,
3396 : : cur_a->bus, cur_a->devid, cur_a->function,
3397 : : domain_id);
3398 : 0 : return ret;
3399 : : }
3400 : :
3401 : : const struct rte_flow_ops enic_fm_flow_ops = {
3402 : : .validate = enic_fm_flow_validate,
3403 : : .create = enic_fm_flow_create,
3404 : : .destroy = enic_fm_flow_destroy,
3405 : : .flush = enic_fm_flow_flush,
3406 : : .query = enic_fm_flow_query,
3407 : : };
3408 : :
3409 : : /* Add a high priority flow that loops representor packets to VF */
3410 : : int
3411 : 0 : enic_fm_add_rep2vf_flow(struct enic_vf_representor *vf)
3412 : : {
3413 : : struct fm_tcam_match_entry *fm_tcam_entry;
3414 : : struct rte_flow *flow0, *flow1;
3415 : : struct fm_action *fm_action;
3416 : : struct rte_flow_error error;
3417 : : struct rte_flow_attr attrs;
3418 : : struct fm_action_op fm_op;
3419 : : struct enic_flowman *fm;
3420 : : struct enic *pf;
3421 : : uint8_t tag;
3422 : :
3423 : 0 : pf = vf->pf;
3424 : 0 : fm = pf->fm;
3425 : 0 : tag = fm->vf_rep_tag;
3426 : 0 : enic_fm_open_scratch(fm);
3427 : 0 : fm_tcam_entry = &fm->tcam_entry;
3428 : 0 : fm_action = &fm->action;
3429 : : /* Egress rule: match WQ ID and tag+hairpin */
3430 : 0 : fm_tcam_entry->ftm_data.fk_wq_id = vf->pf_wq_idx;
3431 : 0 : fm_tcam_entry->ftm_mask.fk_wq_id = 0xffff;
3432 : 0 : fm_tcam_entry->ftm_flags |= FMEF_COUNTER;
3433 : : memset(&fm_op, 0, sizeof(fm_op));
3434 : 0 : fm_op.fa_op = FMOP_TAG;
3435 : 0 : fm_op.tag.tag = tag;
3436 : 0 : enic_fm_append_action_op(fm, &fm_op, &error);
3437 : : memset(&fm_op, 0, sizeof(fm_op));
3438 : 0 : fm_op.fa_op = FMOP_EG_HAIRPIN;
3439 : 0 : enic_fm_append_action_op(fm, &fm_op, &error);
3440 : : memset(&fm_op, 0, sizeof(fm_op));
3441 : 0 : fm_op.fa_op = FMOP_END;
3442 : 0 : enic_fm_append_action_op(fm, &fm_op, &error);
3443 : 0 : attrs.group = 0;
3444 : 0 : attrs.ingress = 0;
3445 : 0 : attrs.egress = 1;
3446 : 0 : attrs.priority = FM_HIGHEST_PRIORITY;
3447 : 0 : flow0 = enic_fm_flow_add_entry(fm, fm_tcam_entry, fm_action,
3448 : : &attrs, &error);
3449 : : enic_fm_close_scratch(fm);
3450 [ # # ]: 0 : if (flow0 == NULL) {
3451 : 0 : ENICPMD_LOG(ERR, "Cannot create flow 0 for representor->VF");
3452 : 0 : return -EINVAL;
3453 : : }
3454 [ # # ]: 0 : LIST_INSERT_HEAD(&pf->flows, flow0, next);
3455 : : /* Make this flow internal, so the user app cannot delete it */
3456 : 0 : flow0->internal = 1;
3457 : 0 : ENICPMD_LOG(DEBUG, "representor->VF %d flow created: wq %d -> tag %d hairpin",
3458 : : vf->vf_id, vf->pf_wq_idx, tag);
3459 : :
3460 : : /* Ingress: steer hairpinned to VF RQ 0 */
3461 : 0 : enic_fm_open_scratch(fm);
3462 : 0 : fm_tcam_entry->ftm_flags |= FMEF_COUNTER;
3463 : 0 : fm_tcam_entry->ftm_data.fk_hdrset[0].fk_metadata |= FKM_EG_HAIRPINNED;
3464 : 0 : fm_tcam_entry->ftm_mask.fk_hdrset[0].fk_metadata |= FKM_EG_HAIRPINNED;
3465 : 0 : fm_tcam_entry->ftm_data.fk_packet_tag = tag;
3466 : 0 : fm_tcam_entry->ftm_mask.fk_packet_tag = 0xff;
3467 : : memset(&fm_op, 0, sizeof(fm_op));
3468 : 0 : fm_op.fa_op = FMOP_RQ_STEER;
3469 : : fm_op.rq_steer.rq_index = 0;
3470 : 0 : fm_op.rq_steer.vnic_handle = vf->enic.fm_vnic_handle;
3471 : 0 : enic_fm_append_action_op(fm, &fm_op, &error);
3472 : : memset(&fm_op, 0, sizeof(fm_op));
3473 : 0 : fm_op.fa_op = FMOP_END;
3474 : 0 : enic_fm_append_action_op(fm, &fm_op, &error);
3475 : 0 : attrs.group = 0;
3476 : 0 : attrs.ingress = 1;
3477 : 0 : attrs.egress = 0;
3478 : 0 : attrs.priority = FM_HIGHEST_PRIORITY;
3479 : 0 : flow1 = enic_fm_flow_add_entry(fm, fm_tcam_entry, fm_action,
3480 : : &attrs, &error);
3481 : : enic_fm_close_scratch(fm);
3482 [ # # ]: 0 : if (flow1 == NULL) {
3483 : 0 : ENICPMD_LOG(ERR, "Cannot create flow 1 for representor->VF");
3484 : 0 : enic_fm_flow_destroy(pf->rte_dev, flow0, &error);
3485 : 0 : return -EINVAL;
3486 : : }
3487 [ # # ]: 0 : LIST_INSERT_HEAD(&pf->flows, flow1, next);
3488 : 0 : flow1->internal = 1;
3489 : 0 : ENICPMD_LOG(DEBUG, "representor->VF %d flow created: tag %d hairpinned -> VF RQ %d",
3490 : : vf->vf_id, tag, fm_op.rq_steer.rq_index);
3491 : 0 : vf->rep2vf_flow[0] = flow0;
3492 : 0 : vf->rep2vf_flow[1] = flow1;
3493 : : /* Done with this tag, use a different one next time */
3494 : 0 : fm->vf_rep_tag++;
3495 : 0 : return 0;
3496 : : }
3497 : :
3498 : : /*
3499 : : * Add a low priority flow that matches all packets from VF and loops them
3500 : : * back to the representor.
3501 : : */
3502 : : int
3503 : 0 : enic_fm_add_vf2rep_flow(struct enic_vf_representor *vf)
3504 : : {
3505 : : struct fm_tcam_match_entry *fm_tcam_entry;
3506 : : struct rte_flow *flow0, *flow1;
3507 : : struct fm_action *fm_action;
3508 : : struct rte_flow_error error;
3509 : : struct rte_flow_attr attrs;
3510 : : struct fm_action_op fm_op;
3511 : : struct enic_flowman *fm;
3512 : : struct enic *pf;
3513 : : uint8_t tag;
3514 : :
3515 : 0 : pf = vf->pf;
3516 : 0 : fm = pf->fm;
3517 : 0 : tag = fm->vf_rep_tag;
3518 : 0 : enic_fm_open_scratch(fm);
3519 : 0 : fm_tcam_entry = &fm->tcam_entry;
3520 : 0 : fm_action = &fm->action;
3521 : : /* Egress rule: match-any and tag+hairpin */
3522 : 0 : fm_tcam_entry->ftm_data.fk_wq_id = 0;
3523 : 0 : fm_tcam_entry->ftm_mask.fk_wq_id = 0xffff;
3524 : 0 : fm_tcam_entry->ftm_data.fk_wq_vnic = vf->enic.fm_vnic_handle;
3525 : 0 : fm_tcam_entry->ftm_flags |= FMEF_COUNTER;
3526 : : memset(&fm_op, 0, sizeof(fm_op));
3527 : 0 : fm_op.fa_op = FMOP_TAG;
3528 : 0 : fm_op.tag.tag = tag;
3529 : 0 : enic_fm_append_action_op(fm, &fm_op, &error);
3530 : : memset(&fm_op, 0, sizeof(fm_op));
3531 : 0 : fm_op.fa_op = FMOP_EG_HAIRPIN;
3532 : 0 : enic_fm_append_action_op(fm, &fm_op, &error);
3533 : : memset(&fm_op, 0, sizeof(fm_op));
3534 : 0 : fm_op.fa_op = FMOP_END;
3535 : 0 : enic_fm_append_action_op(fm, &fm_op, &error);
3536 : 0 : attrs.group = 0;
3537 : 0 : attrs.ingress = 0;
3538 : 0 : attrs.egress = 1;
3539 : 0 : attrs.priority = FM_LOWEST_PRIORITY;
3540 : 0 : flow0 = enic_fm_flow_add_entry(fm, fm_tcam_entry, fm_action,
3541 : : &attrs, &error);
3542 : : enic_fm_close_scratch(fm);
3543 [ # # ]: 0 : if (flow0 == NULL) {
3544 : 0 : ENICPMD_LOG(ERR, "Cannot create flow 0 for VF->representor");
3545 : 0 : return -EINVAL;
3546 : : }
3547 [ # # ]: 0 : LIST_INSERT_HEAD(&pf->flows, flow0, next);
3548 : : /* Make this flow internal, so the user app cannot delete it */
3549 : 0 : flow0->internal = 1;
3550 : 0 : ENICPMD_LOG(DEBUG, "VF %d->representor flow created: wq %d (low prio) -> tag %d hairpin",
3551 : : vf->vf_id, fm_tcam_entry->ftm_data.fk_wq_id, tag);
3552 : :
3553 : : /* Ingress: steer hairpinned to VF rep RQ */
3554 : 0 : enic_fm_open_scratch(fm);
3555 : 0 : fm_tcam_entry->ftm_flags |= FMEF_COUNTER;
3556 : 0 : fm_tcam_entry->ftm_data.fk_hdrset[0].fk_metadata |= FKM_EG_HAIRPINNED;
3557 : 0 : fm_tcam_entry->ftm_mask.fk_hdrset[0].fk_metadata |= FKM_EG_HAIRPINNED;
3558 : 0 : fm_tcam_entry->ftm_data.fk_packet_tag = tag;
3559 : 0 : fm_tcam_entry->ftm_mask.fk_packet_tag = 0xff;
3560 : : memset(&fm_op, 0, sizeof(fm_op));
3561 : 0 : fm_op.fa_op = FMOP_RQ_STEER;
3562 : 0 : fm_op.rq_steer.rq_index = vf->pf_rq_sop_idx;
3563 : 0 : fm_op.rq_steer.vnic_handle = pf->fm_vnic_handle;
3564 : 0 : enic_fm_append_action_op(fm, &fm_op, &error);
3565 : : memset(&fm_op, 0, sizeof(fm_op));
3566 : 0 : fm_op.fa_op = FMOP_END;
3567 : 0 : enic_fm_append_action_op(fm, &fm_op, &error);
3568 : 0 : attrs.group = 0;
3569 : 0 : attrs.ingress = 1;
3570 : 0 : attrs.egress = 0;
3571 : 0 : attrs.priority = FM_HIGHEST_PRIORITY;
3572 : 0 : flow1 = enic_fm_flow_add_entry(fm, fm_tcam_entry, fm_action,
3573 : : &attrs, &error);
3574 : : enic_fm_close_scratch(fm);
3575 [ # # ]: 0 : if (flow1 == NULL) {
3576 : 0 : ENICPMD_LOG(ERR, "Cannot create flow 1 for VF->representor");
3577 : 0 : enic_fm_flow_destroy(pf->rte_dev, flow0, &error);
3578 : 0 : return -EINVAL;
3579 : : }
3580 [ # # ]: 0 : LIST_INSERT_HEAD(&pf->flows, flow1, next);
3581 : 0 : flow1->internal = 1;
3582 : 0 : ENICPMD_LOG(DEBUG, "VF %d->representor flow created: tag %d hairpinned -> PF RQ %d",
3583 : : vf->vf_id, tag, vf->pf_rq_sop_idx);
3584 : 0 : vf->vf2rep_flow[0] = flow0;
3585 : 0 : vf->vf2rep_flow[1] = flow1;
3586 : : /* Done with this tag, use a different one next time */
3587 : 0 : fm->vf_rep_tag++;
3588 : 0 : return 0;
3589 : : }
3590 : :
3591 : : /* Destroy representor flows created by enic_fm_add_{rep2vf,vf2rep}_flow */
3592 : : static void
3593 : 0 : delete_rep_flows(struct enic *enic)
3594 : : {
3595 : : struct enic_vf_representor *vf;
3596 : : struct rte_flow_error error;
3597 : : struct rte_eth_dev *dev;
3598 : : uint32_t i;
3599 : :
3600 : : RTE_ASSERT(rte_eth_dev_is_repr(enic->rte_dev));
3601 : : vf = VF_ENIC_TO_VF_REP(enic);
3602 : 0 : dev = vf->pf->rte_dev;
3603 [ # # ]: 0 : for (i = 0; i < ARRAY_SIZE(vf->vf2rep_flow); i++) {
3604 [ # # ]: 0 : if (vf->vf2rep_flow[i])
3605 : 0 : enic_fm_flow_destroy(dev, vf->vf2rep_flow[i], &error);
3606 : : }
3607 [ # # ]: 0 : for (i = 0; i < ARRAY_SIZE(vf->rep2vf_flow); i++) {
3608 [ # # ]: 0 : if (vf->rep2vf_flow[i])
3609 : 0 : enic_fm_flow_destroy(dev, vf->rep2vf_flow[i], &error);
3610 : : }
3611 : 0 : }
3612 : :
3613 : : static struct enic_flowman *
3614 : 0 : begin_fm(struct enic *enic)
3615 : : {
3616 : : struct enic_vf_representor *vf;
3617 : : struct enic_flowman *fm;
3618 : :
3619 : : /* Representor uses PF flowman */
3620 [ # # ]: 0 : if (rte_eth_dev_is_repr(enic->rte_dev)) {
3621 : : vf = VF_ENIC_TO_VF_REP(enic);
3622 : 0 : fm = vf->pf->fm;
3623 : : } else {
3624 : 0 : fm = enic->fm;
3625 : : }
3626 : : /* Save the API caller and lock if representors exist */
3627 [ # # ]: 0 : if (fm) {
3628 [ # # ]: 0 : if (fm->owner_enic->switchdev_mode)
3629 : 0 : rte_spinlock_lock(&fm->lock);
3630 : 0 : fm->user_enic = enic;
3631 : : }
3632 : 0 : return fm;
3633 : : }
3634 : :
3635 : : static void
3636 : : end_fm(struct enic_flowman *fm)
3637 : : {
3638 : 0 : fm->user_enic = NULL;
3639 [ # # # # : 0 : if (fm->owner_enic->switchdev_mode)
# # # # #
# ]
3640 : 0 : rte_spinlock_unlock(&fm->lock);
3641 : : }
|