1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright (c) 2022 NVIDIA Corporation & Affiliates
3 */
4
5 #include <rte_flow.h>
6
7 #include <mlx5_malloc.h>
8 #include "mlx5_defs.h"
9 #include "mlx5_flow.h"
10 #include "mlx5_rx.h"
11
12 #if defined(HAVE_IBV_FLOW_DV_SUPPORT) || !defined(HAVE_INFINIBAND_VERBS_H)
13
14 /* The maximum actions support in the flow. */
15 #define MLX5_HW_MAX_ACTS 16
16
17 /* Default push burst threshold. */
18 #define BURST_THR 32u
19
20 /* Default queue to flush the flows. */
21 #define MLX5_DEFAULT_FLUSH_QUEUE 0
22
23 const struct mlx5_flow_driver_ops mlx5_flow_hw_drv_ops;
24
25 /* DR action flags with different table. */
26 static uint32_t mlx5_hw_act_flag[MLX5_HW_ACTION_FLAG_MAX]
27 [MLX5DR_TABLE_TYPE_MAX] = {
28 {
29 MLX5DR_ACTION_FLAG_ROOT_RX,
30 MLX5DR_ACTION_FLAG_ROOT_TX,
31 MLX5DR_ACTION_FLAG_ROOT_FDB,
32 },
33 {
34 MLX5DR_ACTION_FLAG_HWS_RX,
35 MLX5DR_ACTION_FLAG_HWS_TX,
36 MLX5DR_ACTION_FLAG_HWS_FDB,
37 },
38 };
39
40 /**
41 * Set rxq flag.
42 *
43 * @param[in] dev
44 * Pointer to the rte_eth_dev structure.
45 * @param[in] enable
46 * Flag to enable or not.
47 */
48 static void
flow_hw_rxq_flag_set(struct rte_eth_dev * dev,bool enable)49 flow_hw_rxq_flag_set(struct rte_eth_dev *dev, bool enable)
50 {
51 struct mlx5_priv *priv = dev->data->dev_private;
52 unsigned int i;
53
54 if ((!priv->mark_enabled && !enable) ||
55 (priv->mark_enabled && enable))
56 return;
57 for (i = 0; i < priv->rxqs_n; ++i) {
58 struct mlx5_rxq_ctrl *rxq_ctrl = mlx5_rxq_ctrl_get(dev, i);
59
60 rxq_ctrl->rxq.mark = enable;
61 }
62 priv->mark_enabled = enable;
63 }
64
65 /**
66 * Generate the pattern item flags.
67 * Will be used for shared RSS action.
68 *
69 * @param[in] items
70 * Pointer to the list of items.
71 *
72 * @return
73 * Item flags.
74 */
75 static uint64_t
flow_hw_rss_item_flags_get(const struct rte_flow_item items[])76 flow_hw_rss_item_flags_get(const struct rte_flow_item items[])
77 {
78 uint64_t item_flags = 0;
79 uint64_t last_item = 0;
80
81 for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) {
82 int tunnel = !!(item_flags & MLX5_FLOW_LAYER_TUNNEL);
83 int item_type = items->type;
84
85 switch (item_type) {
86 case RTE_FLOW_ITEM_TYPE_IPV4:
87 last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV4 :
88 MLX5_FLOW_LAYER_OUTER_L3_IPV4;
89 break;
90 case RTE_FLOW_ITEM_TYPE_IPV6:
91 last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV6 :
92 MLX5_FLOW_LAYER_OUTER_L3_IPV6;
93 break;
94 case RTE_FLOW_ITEM_TYPE_TCP:
95 last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L4_TCP :
96 MLX5_FLOW_LAYER_OUTER_L4_TCP;
97 break;
98 case RTE_FLOW_ITEM_TYPE_UDP:
99 last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L4_UDP :
100 MLX5_FLOW_LAYER_OUTER_L4_UDP;
101 break;
102 case RTE_FLOW_ITEM_TYPE_GRE:
103 last_item = MLX5_FLOW_LAYER_GRE;
104 break;
105 case RTE_FLOW_ITEM_TYPE_NVGRE:
106 last_item = MLX5_FLOW_LAYER_GRE;
107 break;
108 case RTE_FLOW_ITEM_TYPE_VXLAN:
109 last_item = MLX5_FLOW_LAYER_VXLAN;
110 break;
111 case RTE_FLOW_ITEM_TYPE_VXLAN_GPE:
112 last_item = MLX5_FLOW_LAYER_VXLAN_GPE;
113 break;
114 case RTE_FLOW_ITEM_TYPE_GENEVE:
115 last_item = MLX5_FLOW_LAYER_GENEVE;
116 break;
117 case RTE_FLOW_ITEM_TYPE_MPLS:
118 last_item = MLX5_FLOW_LAYER_MPLS;
119 break;
120 case RTE_FLOW_ITEM_TYPE_GTP:
121 last_item = MLX5_FLOW_LAYER_GTP;
122 break;
123 default:
124 break;
125 }
126 item_flags |= last_item;
127 }
128 return item_flags;
129 }
130
131 /**
132 * Register destination table DR jump action.
133 *
134 * @param[in] dev
135 * Pointer to the rte_eth_dev structure.
136 * @param[in] table_attr
137 * Pointer to the flow attributes.
138 * @param[in] dest_group
139 * The destination group ID.
140 * @param[out] error
141 * Pointer to error structure.
142 *
143 * @return
144 * Table on success, NULL otherwise and rte_errno is set.
145 */
146 static struct mlx5_hw_jump_action *
flow_hw_jump_action_register(struct rte_eth_dev * dev,const struct rte_flow_attr * attr,uint32_t dest_group,struct rte_flow_error * error)147 flow_hw_jump_action_register(struct rte_eth_dev *dev,
148 const struct rte_flow_attr *attr,
149 uint32_t dest_group,
150 struct rte_flow_error *error)
151 {
152 struct mlx5_priv *priv = dev->data->dev_private;
153 struct rte_flow_attr jattr = *attr;
154 struct mlx5_flow_group *grp;
155 struct mlx5_flow_cb_ctx ctx = {
156 .dev = dev,
157 .error = error,
158 .data = &jattr,
159 };
160 struct mlx5_list_entry *ge;
161
162 jattr.group = dest_group;
163 ge = mlx5_hlist_register(priv->sh->flow_tbls, dest_group, &ctx);
164 if (!ge)
165 return NULL;
166 grp = container_of(ge, struct mlx5_flow_group, entry);
167 return &grp->jump;
168 }
169
170 /**
171 * Release jump action.
172 *
173 * @param[in] dev
174 * Pointer to the rte_eth_dev structure.
175 * @param[in] jump
176 * Pointer to the jump action.
177 */
178
179 static void
flow_hw_jump_release(struct rte_eth_dev * dev,struct mlx5_hw_jump_action * jump)180 flow_hw_jump_release(struct rte_eth_dev *dev, struct mlx5_hw_jump_action *jump)
181 {
182 struct mlx5_priv *priv = dev->data->dev_private;
183 struct mlx5_flow_group *grp;
184
185 grp = container_of
186 (jump, struct mlx5_flow_group, jump);
187 mlx5_hlist_unregister(priv->sh->flow_tbls, &grp->entry);
188 }
189
190 /**
191 * Register queue/RSS action.
192 *
193 * @param[in] dev
194 * Pointer to the rte_eth_dev structure.
195 * @param[in] hws_flags
196 * DR action flags.
197 * @param[in] action
198 * rte flow action.
199 *
200 * @return
201 * Table on success, NULL otherwise and rte_errno is set.
202 */
203 static inline struct mlx5_hrxq*
flow_hw_tir_action_register(struct rte_eth_dev * dev,uint32_t hws_flags,const struct rte_flow_action * action)204 flow_hw_tir_action_register(struct rte_eth_dev *dev,
205 uint32_t hws_flags,
206 const struct rte_flow_action *action)
207 {
208 struct mlx5_flow_rss_desc rss_desc = {
209 .hws_flags = hws_flags,
210 };
211 struct mlx5_hrxq *hrxq;
212
213 if (action->type == RTE_FLOW_ACTION_TYPE_QUEUE) {
214 const struct rte_flow_action_queue *queue = action->conf;
215
216 rss_desc.const_q = &queue->index;
217 rss_desc.queue_num = 1;
218 } else {
219 const struct rte_flow_action_rss *rss = action->conf;
220
221 rss_desc.queue_num = rss->queue_num;
222 rss_desc.const_q = rss->queue;
223 memcpy(rss_desc.key,
224 !rss->key ? rss_hash_default_key : rss->key,
225 MLX5_RSS_HASH_KEY_LEN);
226 rss_desc.key_len = MLX5_RSS_HASH_KEY_LEN;
227 rss_desc.types = !rss->types ? RTE_ETH_RSS_IP : rss->types;
228 flow_dv_hashfields_set(0, &rss_desc, &rss_desc.hash_fields);
229 flow_dv_action_rss_l34_hash_adjust(rss->types,
230 &rss_desc.hash_fields);
231 if (rss->level > 1) {
232 rss_desc.hash_fields |= IBV_RX_HASH_INNER;
233 rss_desc.tunnel = 1;
234 }
235 }
236 hrxq = mlx5_hrxq_get(dev, &rss_desc);
237 return hrxq;
238 }
239
240 /**
241 * Destroy DR actions created by action template.
242 *
243 * For DR actions created during table creation's action translate.
244 * Need to destroy the DR action when destroying the table.
245 *
246 * @param[in] dev
247 * Pointer to the rte_eth_dev structure.
248 * @param[in] acts
249 * Pointer to the template HW steering DR actions.
250 */
251 static void
__flow_hw_action_template_destroy(struct rte_eth_dev * dev,struct mlx5_hw_actions * acts)252 __flow_hw_action_template_destroy(struct rte_eth_dev *dev,
253 struct mlx5_hw_actions *acts)
254 {
255 struct mlx5_priv *priv = dev->data->dev_private;
256
257 if (acts->jump) {
258 struct mlx5_flow_group *grp;
259
260 grp = container_of
261 (acts->jump, struct mlx5_flow_group, jump);
262 mlx5_hlist_unregister(priv->sh->flow_tbls, &grp->entry);
263 acts->jump = NULL;
264 }
265 }
266
267 /**
268 * Append dynamic action to the dynamic action list.
269 *
270 * @param[in] priv
271 * Pointer to the port private data structure.
272 * @param[in] acts
273 * Pointer to the template HW steering DR actions.
274 * @param[in] type
275 * Action type.
276 * @param[in] action_src
277 * Offset of source rte flow action.
278 * @param[in] action_dst
279 * Offset of destination DR action.
280 *
281 * @return
282 * 0 on success, negative value otherwise and rte_errno is set.
283 */
284 static __rte_always_inline struct mlx5_action_construct_data *
__flow_hw_act_data_alloc(struct mlx5_priv * priv,enum rte_flow_action_type type,uint16_t action_src,uint16_t action_dst)285 __flow_hw_act_data_alloc(struct mlx5_priv *priv,
286 enum rte_flow_action_type type,
287 uint16_t action_src,
288 uint16_t action_dst)
289 {
290 struct mlx5_action_construct_data *act_data;
291 uint32_t idx = 0;
292
293 act_data = mlx5_ipool_zmalloc(priv->acts_ipool, &idx);
294 if (!act_data)
295 return NULL;
296 act_data->idx = idx;
297 act_data->type = type;
298 act_data->action_src = action_src;
299 act_data->action_dst = action_dst;
300 return act_data;
301 }
302
303 /**
304 * Append dynamic action to the dynamic action list.
305 *
306 * @param[in] priv
307 * Pointer to the port private data structure.
308 * @param[in] acts
309 * Pointer to the template HW steering DR actions.
310 * @param[in] type
311 * Action type.
312 * @param[in] action_src
313 * Offset of source rte flow action.
314 * @param[in] action_dst
315 * Offset of destination DR action.
316 *
317 * @return
318 * 0 on success, negative value otherwise and rte_errno is set.
319 */
320 static __rte_always_inline int
__flow_hw_act_data_general_append(struct mlx5_priv * priv,struct mlx5_hw_actions * acts,enum rte_flow_action_type type,uint16_t action_src,uint16_t action_dst)321 __flow_hw_act_data_general_append(struct mlx5_priv *priv,
322 struct mlx5_hw_actions *acts,
323 enum rte_flow_action_type type,
324 uint16_t action_src,
325 uint16_t action_dst)
326 { struct mlx5_action_construct_data *act_data;
327
328 act_data = __flow_hw_act_data_alloc(priv, type, action_src, action_dst);
329 if (!act_data)
330 return -1;
331 LIST_INSERT_HEAD(&acts->act_list, act_data, next);
332 return 0;
333 }
334
335 /**
336 * Append dynamic encap action to the dynamic action list.
337 *
338 * @param[in] priv
339 * Pointer to the port private data structure.
340 * @param[in] acts
341 * Pointer to the template HW steering DR actions.
342 * @param[in] type
343 * Action type.
344 * @param[in] action_src
345 * Offset of source rte flow action.
346 * @param[in] action_dst
347 * Offset of destination DR action.
348 * @param[in] encap_src
349 * Offset of source encap raw data.
350 * @param[in] encap_dst
351 * Offset of destination encap raw data.
352 * @param[in] len
353 * Length of the data to be updated.
354 *
355 * @return
356 * 0 on success, negative value otherwise and rte_errno is set.
357 */
358 static __rte_always_inline int
__flow_hw_act_data_encap_append(struct mlx5_priv * priv,struct mlx5_hw_actions * acts,enum rte_flow_action_type type,uint16_t action_src,uint16_t action_dst,uint16_t encap_src,uint16_t encap_dst,uint16_t len)359 __flow_hw_act_data_encap_append(struct mlx5_priv *priv,
360 struct mlx5_hw_actions *acts,
361 enum rte_flow_action_type type,
362 uint16_t action_src,
363 uint16_t action_dst,
364 uint16_t encap_src,
365 uint16_t encap_dst,
366 uint16_t len)
367 { struct mlx5_action_construct_data *act_data;
368
369 act_data = __flow_hw_act_data_alloc(priv, type, action_src, action_dst);
370 if (!act_data)
371 return -1;
372 act_data->encap.src = encap_src;
373 act_data->encap.dst = encap_dst;
374 act_data->encap.len = len;
375 LIST_INSERT_HEAD(&acts->act_list, act_data, next);
376 return 0;
377 }
378
379 /**
380 * Append shared RSS action to the dynamic action list.
381 *
382 * @param[in] priv
383 * Pointer to the port private data structure.
384 * @param[in] acts
385 * Pointer to the template HW steering DR actions.
386 * @param[in] type
387 * Action type.
388 * @param[in] action_src
389 * Offset of source rte flow action.
390 * @param[in] action_dst
391 * Offset of destination DR action.
392 * @param[in] idx
393 * Shared RSS index.
394 * @param[in] rss
395 * Pointer to the shared RSS info.
396 *
397 * @return
398 * 0 on success, negative value otherwise and rte_errno is set.
399 */
400 static __rte_always_inline int
__flow_hw_act_data_shared_rss_append(struct mlx5_priv * priv,struct mlx5_hw_actions * acts,enum rte_flow_action_type type,uint16_t action_src,uint16_t action_dst,uint32_t idx,struct mlx5_shared_action_rss * rss)401 __flow_hw_act_data_shared_rss_append(struct mlx5_priv *priv,
402 struct mlx5_hw_actions *acts,
403 enum rte_flow_action_type type,
404 uint16_t action_src,
405 uint16_t action_dst,
406 uint32_t idx,
407 struct mlx5_shared_action_rss *rss)
408 { struct mlx5_action_construct_data *act_data;
409
410 act_data = __flow_hw_act_data_alloc(priv, type, action_src, action_dst);
411 if (!act_data)
412 return -1;
413 act_data->shared_rss.level = rss->origin.level;
414 act_data->shared_rss.types = !rss->origin.types ? RTE_ETH_RSS_IP :
415 rss->origin.types;
416 act_data->shared_rss.idx = idx;
417 LIST_INSERT_HEAD(&acts->act_list, act_data, next);
418 return 0;
419 }
420
421 /**
422 * Translate shared indirect action.
423 *
424 * @param[in] dev
425 * Pointer to the rte_eth_dev data structure.
426 * @param[in] action
427 * Pointer to the shared indirect rte_flow action.
428 * @param[in] acts
429 * Pointer to the template HW steering DR actions.
430 * @param[in] action_src
431 * Offset of source rte flow action.
432 * @param[in] action_dst
433 * Offset of destination DR action.
434 *
435 * @return
436 * 0 on success, negative value otherwise and rte_errno is set.
437 */
438 static __rte_always_inline int
flow_hw_shared_action_translate(struct rte_eth_dev * dev,const struct rte_flow_action * action,struct mlx5_hw_actions * acts,uint16_t action_src,uint16_t action_dst)439 flow_hw_shared_action_translate(struct rte_eth_dev *dev,
440 const struct rte_flow_action *action,
441 struct mlx5_hw_actions *acts,
442 uint16_t action_src,
443 uint16_t action_dst)
444 {
445 struct mlx5_priv *priv = dev->data->dev_private;
446 struct mlx5_shared_action_rss *shared_rss;
447 uint32_t act_idx = (uint32_t)(uintptr_t)action->conf;
448 uint32_t type = act_idx >> MLX5_INDIRECT_ACTION_TYPE_OFFSET;
449 uint32_t idx = act_idx &
450 ((1u << MLX5_INDIRECT_ACTION_TYPE_OFFSET) - 1);
451
452 switch (type) {
453 case MLX5_INDIRECT_ACTION_TYPE_RSS:
454 shared_rss = mlx5_ipool_get
455 (priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS], idx);
456 if (!shared_rss || __flow_hw_act_data_shared_rss_append
457 (priv, acts,
458 (enum rte_flow_action_type)MLX5_RTE_FLOW_ACTION_TYPE_RSS,
459 action_src, action_dst, idx, shared_rss))
460 return -1;
461 break;
462 default:
463 DRV_LOG(WARNING, "Unsupported shared action type:%d", type);
464 break;
465 }
466 return 0;
467 }
468
469 /**
470 * Translate encap items to encapsulation list.
471 *
472 * @param[in] dev
473 * Pointer to the rte_eth_dev data structure.
474 * @param[in] acts
475 * Pointer to the template HW steering DR actions.
476 * @param[in] type
477 * Action type.
478 * @param[in] action_src
479 * Offset of source rte flow action.
480 * @param[in] action_dst
481 * Offset of destination DR action.
482 * @param[in] items
483 * Encap item pattern.
484 * @param[in] items_m
485 * Encap item mask indicates which part are constant and dynamic.
486 *
487 * @return
488 * 0 on success, negative value otherwise and rte_errno is set.
489 */
490 static __rte_always_inline int
flow_hw_encap_item_translate(struct rte_eth_dev * dev,struct mlx5_hw_actions * acts,enum rte_flow_action_type type,uint16_t action_src,uint16_t action_dst,const struct rte_flow_item * items,const struct rte_flow_item * items_m)491 flow_hw_encap_item_translate(struct rte_eth_dev *dev,
492 struct mlx5_hw_actions *acts,
493 enum rte_flow_action_type type,
494 uint16_t action_src,
495 uint16_t action_dst,
496 const struct rte_flow_item *items,
497 const struct rte_flow_item *items_m)
498 {
499 struct mlx5_priv *priv = dev->data->dev_private;
500 size_t len, total_len = 0;
501 uint32_t i = 0;
502
503 for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++, items_m++, i++) {
504 len = flow_dv_get_item_hdr_len(items->type);
505 if ((!items_m->spec ||
506 memcmp(items_m->spec, items->spec, len)) &&
507 __flow_hw_act_data_encap_append(priv, acts, type,
508 action_src, action_dst, i,
509 total_len, len))
510 return -1;
511 total_len += len;
512 }
513 return 0;
514 }
515
516 /**
517 * Translate rte_flow actions to DR action.
518 *
519 * As the action template has already indicated the actions. Translate
520 * the rte_flow actions to DR action if possbile. So in flow create
521 * stage we will save cycles from handing the actions' organizing.
522 * For the actions with limited information, need to add these to a
523 * list.
524 *
525 * @param[in] dev
526 * Pointer to the rte_eth_dev structure.
527 * @param[in] table_attr
528 * Pointer to the table attributes.
529 * @param[in] item_templates
530 * Item template array to be binded to the table.
531 * @param[in/out] acts
532 * Pointer to the template HW steering DR actions.
533 * @param[in] at
534 * Action template.
535 * @param[out] error
536 * Pointer to error structure.
537 *
538 * @return
539 * Table on success, NULL otherwise and rte_errno is set.
540 */
541 static int
flow_hw_actions_translate(struct rte_eth_dev * dev,const struct rte_flow_template_table_attr * table_attr,struct mlx5_hw_actions * acts,struct rte_flow_actions_template * at,struct rte_flow_error * error)542 flow_hw_actions_translate(struct rte_eth_dev *dev,
543 const struct rte_flow_template_table_attr *table_attr,
544 struct mlx5_hw_actions *acts,
545 struct rte_flow_actions_template *at,
546 struct rte_flow_error *error)
547 {
548 struct mlx5_priv *priv = dev->data->dev_private;
549 const struct rte_flow_attr *attr = &table_attr->flow_attr;
550 struct rte_flow_action *actions = at->actions;
551 struct rte_flow_action *action_start = actions;
552 struct rte_flow_action *masks = at->masks;
553 enum mlx5dr_action_reformat_type refmt_type = 0;
554 const struct rte_flow_action_raw_encap *raw_encap_data;
555 const struct rte_flow_item *enc_item = NULL, *enc_item_m = NULL;
556 uint16_t reformat_pos = MLX5_HW_MAX_ACTS, reformat_src = 0;
557 uint8_t *encap_data = NULL;
558 size_t data_size = 0;
559 bool actions_end = false;
560 uint32_t type, i;
561 int err;
562
563 if (attr->transfer)
564 type = MLX5DR_TABLE_TYPE_FDB;
565 else if (attr->egress)
566 type = MLX5DR_TABLE_TYPE_NIC_TX;
567 else
568 type = MLX5DR_TABLE_TYPE_NIC_RX;
569 for (i = 0; !actions_end; actions++, masks++) {
570 switch (actions->type) {
571 case RTE_FLOW_ACTION_TYPE_INDIRECT:
572 if (!attr->group) {
573 DRV_LOG(ERR, "Indirect action is not supported in root table.");
574 goto err;
575 }
576 if (actions->conf && masks->conf) {
577 if (flow_hw_shared_action_translate
578 (dev, actions, acts, actions - action_start, i))
579 goto err;
580 } else if (__flow_hw_act_data_general_append
581 (priv, acts, actions->type,
582 actions - action_start, i)){
583 goto err;
584 }
585 i++;
586 break;
587 case RTE_FLOW_ACTION_TYPE_VOID:
588 break;
589 case RTE_FLOW_ACTION_TYPE_DROP:
590 acts->rule_acts[i++].action =
591 priv->hw_drop[!!attr->group][type];
592 break;
593 case RTE_FLOW_ACTION_TYPE_MARK:
594 acts->mark = true;
595 if (masks->conf)
596 acts->rule_acts[i].tag.value =
597 mlx5_flow_mark_set
598 (((const struct rte_flow_action_mark *)
599 (masks->conf))->id);
600 else if (__flow_hw_act_data_general_append(priv, acts,
601 actions->type, actions - action_start, i))
602 goto err;
603 acts->rule_acts[i++].action =
604 priv->hw_tag[!!attr->group];
605 flow_hw_rxq_flag_set(dev, true);
606 break;
607 case RTE_FLOW_ACTION_TYPE_JUMP:
608 if (masks->conf) {
609 uint32_t jump_group =
610 ((const struct rte_flow_action_jump *)
611 actions->conf)->group;
612 acts->jump = flow_hw_jump_action_register
613 (dev, attr, jump_group, error);
614 if (!acts->jump)
615 goto err;
616 acts->rule_acts[i].action = (!!attr->group) ?
617 acts->jump->hws_action :
618 acts->jump->root_action;
619 } else if (__flow_hw_act_data_general_append
620 (priv, acts, actions->type,
621 actions - action_start, i)){
622 goto err;
623 }
624 i++;
625 break;
626 case RTE_FLOW_ACTION_TYPE_QUEUE:
627 if (masks->conf) {
628 acts->tir = flow_hw_tir_action_register
629 (dev,
630 mlx5_hw_act_flag[!!attr->group][type],
631 actions);
632 if (!acts->tir)
633 goto err;
634 acts->rule_acts[i].action =
635 acts->tir->action;
636 } else if (__flow_hw_act_data_general_append
637 (priv, acts, actions->type,
638 actions - action_start, i)) {
639 goto err;
640 }
641 i++;
642 break;
643 case RTE_FLOW_ACTION_TYPE_RSS:
644 if (masks->conf) {
645 acts->tir = flow_hw_tir_action_register
646 (dev,
647 mlx5_hw_act_flag[!!attr->group][type],
648 actions);
649 if (!acts->tir)
650 goto err;
651 acts->rule_acts[i].action =
652 acts->tir->action;
653 } else if (__flow_hw_act_data_general_append
654 (priv, acts, actions->type,
655 actions - action_start, i)) {
656 goto err;
657 }
658 i++;
659 break;
660 case RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP:
661 MLX5_ASSERT(reformat_pos == MLX5_HW_MAX_ACTS);
662 enc_item = ((const struct rte_flow_action_vxlan_encap *)
663 actions->conf)->definition;
664 enc_item_m =
665 ((const struct rte_flow_action_vxlan_encap *)
666 masks->conf)->definition;
667 reformat_pos = i++;
668 reformat_src = actions - action_start;
669 refmt_type = MLX5DR_ACTION_REFORMAT_TYPE_L2_TO_TNL_L2;
670 break;
671 case RTE_FLOW_ACTION_TYPE_NVGRE_ENCAP:
672 MLX5_ASSERT(reformat_pos == MLX5_HW_MAX_ACTS);
673 enc_item = ((const struct rte_flow_action_nvgre_encap *)
674 actions->conf)->definition;
675 enc_item_m =
676 ((const struct rte_flow_action_nvgre_encap *)
677 actions->conf)->definition;
678 reformat_pos = i++;
679 reformat_src = actions - action_start;
680 refmt_type = MLX5DR_ACTION_REFORMAT_TYPE_L2_TO_TNL_L2;
681 break;
682 case RTE_FLOW_ACTION_TYPE_VXLAN_DECAP:
683 case RTE_FLOW_ACTION_TYPE_NVGRE_DECAP:
684 MLX5_ASSERT(reformat_pos == MLX5_HW_MAX_ACTS);
685 reformat_pos = i++;
686 refmt_type = MLX5DR_ACTION_REFORMAT_TYPE_TNL_L2_TO_L2;
687 break;
688 case RTE_FLOW_ACTION_TYPE_RAW_ENCAP:
689 raw_encap_data =
690 (const struct rte_flow_action_raw_encap *)
691 actions->conf;
692 encap_data = raw_encap_data->data;
693 data_size = raw_encap_data->size;
694 if (reformat_pos != MLX5_HW_MAX_ACTS) {
695 refmt_type = data_size <
696 MLX5_ENCAPSULATION_DECISION_SIZE ?
697 MLX5DR_ACTION_REFORMAT_TYPE_TNL_L3_TO_L2 :
698 MLX5DR_ACTION_REFORMAT_TYPE_L2_TO_TNL_L3;
699 } else {
700 reformat_pos = i++;
701 refmt_type =
702 MLX5DR_ACTION_REFORMAT_TYPE_L2_TO_TNL_L2;
703 }
704 reformat_src = actions - action_start;
705 break;
706 case RTE_FLOW_ACTION_TYPE_RAW_DECAP:
707 reformat_pos = i++;
708 refmt_type = MLX5DR_ACTION_REFORMAT_TYPE_TNL_L2_TO_L2;
709 break;
710 case RTE_FLOW_ACTION_TYPE_END:
711 actions_end = true;
712 break;
713 default:
714 break;
715 }
716 }
717 if (reformat_pos != MLX5_HW_MAX_ACTS) {
718 uint8_t buf[MLX5_ENCAP_MAX_LEN];
719
720 if (enc_item) {
721 MLX5_ASSERT(!encap_data);
722 if (flow_dv_convert_encap_data
723 (enc_item, buf, &data_size, error) ||
724 flow_hw_encap_item_translate
725 (dev, acts, (action_start + reformat_src)->type,
726 reformat_src, reformat_pos,
727 enc_item, enc_item_m))
728 goto err;
729 encap_data = buf;
730 } else if (encap_data && __flow_hw_act_data_encap_append
731 (priv, acts,
732 (action_start + reformat_src)->type,
733 reformat_src, reformat_pos, 0, 0, data_size)) {
734 goto err;
735 }
736 acts->encap_decap = mlx5_malloc(MLX5_MEM_ZERO,
737 sizeof(*acts->encap_decap) + data_size,
738 0, SOCKET_ID_ANY);
739 if (!acts->encap_decap)
740 goto err;
741 if (data_size) {
742 acts->encap_decap->data_size = data_size;
743 memcpy(acts->encap_decap->data, encap_data, data_size);
744 }
745 acts->encap_decap->action = mlx5dr_action_create_reformat
746 (priv->dr_ctx, refmt_type,
747 data_size, encap_data,
748 rte_log2_u32(table_attr->nb_flows),
749 mlx5_hw_act_flag[!!attr->group][type]);
750 if (!acts->encap_decap->action)
751 goto err;
752 acts->rule_acts[reformat_pos].action =
753 acts->encap_decap->action;
754 acts->encap_decap_pos = reformat_pos;
755 }
756 acts->acts_num = i;
757 return 0;
758 err:
759 err = rte_errno;
760 __flow_hw_action_template_destroy(dev, acts);
761 return rte_flow_error_set(error, err,
762 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
763 "fail to create rte table");
764 }
765
766 /**
767 * Get shared indirect action.
768 *
769 * @param[in] dev
770 * Pointer to the rte_eth_dev data structure.
771 * @param[in] act_data
772 * Pointer to the recorded action construct data.
773 * @param[in] item_flags
774 * The matcher itme_flags used for RSS lookup.
775 * @param[in] rule_act
776 * Pointer to the shared action's destination rule DR action.
777 *
778 * @return
779 * 0 on success, negative value otherwise and rte_errno is set.
780 */
781 static __rte_always_inline int
flow_hw_shared_action_get(struct rte_eth_dev * dev,struct mlx5_action_construct_data * act_data,const uint64_t item_flags,struct mlx5dr_rule_action * rule_act)782 flow_hw_shared_action_get(struct rte_eth_dev *dev,
783 struct mlx5_action_construct_data *act_data,
784 const uint64_t item_flags,
785 struct mlx5dr_rule_action *rule_act)
786 {
787 struct mlx5_priv *priv = dev->data->dev_private;
788 struct mlx5_flow_rss_desc rss_desc = { 0 };
789 uint64_t hash_fields = 0;
790 uint32_t hrxq_idx = 0;
791 struct mlx5_hrxq *hrxq = NULL;
792 int act_type = act_data->type;
793
794 switch (act_type) {
795 case MLX5_RTE_FLOW_ACTION_TYPE_RSS:
796 rss_desc.level = act_data->shared_rss.level;
797 rss_desc.types = act_data->shared_rss.types;
798 flow_dv_hashfields_set(item_flags, &rss_desc, &hash_fields);
799 hrxq_idx = flow_dv_action_rss_hrxq_lookup
800 (dev, act_data->shared_rss.idx, hash_fields);
801 if (hrxq_idx)
802 hrxq = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_HRXQ],
803 hrxq_idx);
804 if (hrxq) {
805 rule_act->action = hrxq->action;
806 return 0;
807 }
808 break;
809 default:
810 DRV_LOG(WARNING, "Unsupported shared action type:%d",
811 act_data->type);
812 break;
813 }
814 return -1;
815 }
816
817 /**
818 * Construct shared indirect action.
819 *
820 * @param[in] dev
821 * Pointer to the rte_eth_dev data structure.
822 * @param[in] action
823 * Pointer to the shared indirect rte_flow action.
824 * @param[in] table
825 * Pointer to the flow table.
826 * @param[in] it_idx
827 * Item template index the action template refer to.
828 * @param[in] rule_act
829 * Pointer to the shared action's destination rule DR action.
830 *
831 * @return
832 * 0 on success, negative value otherwise and rte_errno is set.
833 */
834 static __rte_always_inline int
flow_hw_shared_action_construct(struct rte_eth_dev * dev,const struct rte_flow_action * action,struct rte_flow_template_table * table,const uint8_t it_idx,struct mlx5dr_rule_action * rule_act)835 flow_hw_shared_action_construct(struct rte_eth_dev *dev,
836 const struct rte_flow_action *action,
837 struct rte_flow_template_table *table,
838 const uint8_t it_idx,
839 struct mlx5dr_rule_action *rule_act)
840 {
841 struct mlx5_priv *priv = dev->data->dev_private;
842 struct mlx5_action_construct_data act_data;
843 struct mlx5_shared_action_rss *shared_rss;
844 uint32_t act_idx = (uint32_t)(uintptr_t)action->conf;
845 uint32_t type = act_idx >> MLX5_INDIRECT_ACTION_TYPE_OFFSET;
846 uint32_t idx = act_idx &
847 ((1u << MLX5_INDIRECT_ACTION_TYPE_OFFSET) - 1);
848 uint64_t item_flags;
849
850 memset(&act_data, 0, sizeof(act_data));
851 switch (type) {
852 case MLX5_INDIRECT_ACTION_TYPE_RSS:
853 act_data.type = MLX5_RTE_FLOW_ACTION_TYPE_RSS;
854 shared_rss = mlx5_ipool_get
855 (priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS], idx);
856 if (!shared_rss)
857 return -1;
858 act_data.shared_rss.idx = idx;
859 act_data.shared_rss.level = shared_rss->origin.level;
860 act_data.shared_rss.types = !shared_rss->origin.types ?
861 RTE_ETH_RSS_IP :
862 shared_rss->origin.types;
863 item_flags = table->its[it_idx]->item_flags;
864 if (flow_hw_shared_action_get
865 (dev, &act_data, item_flags, rule_act))
866 return -1;
867 break;
868 default:
869 DRV_LOG(WARNING, "Unsupported shared action type:%d", type);
870 break;
871 }
872 return 0;
873 }
874
875 /**
876 * Construct flow action array.
877 *
878 * For action template contains dynamic actions, these actions need to
879 * be updated according to the rte_flow action during flow creation.
880 *
881 * @param[in] dev
882 * Pointer to the rte_eth_dev structure.
883 * @param[in] job
884 * Pointer to job descriptor.
885 * @param[in] hw_acts
886 * Pointer to translated actions from template.
887 * @param[in] it_idx
888 * Item template index the action template refer to.
889 * @param[in] actions
890 * Array of rte_flow action need to be checked.
891 * @param[in] rule_acts
892 * Array of DR rule actions to be used during flow creation..
893 * @param[in] acts_num
894 * Pointer to the real acts_num flow has.
895 *
896 * @return
897 * 0 on success, negative value otherwise and rte_errno is set.
898 */
899 static __rte_always_inline int
flow_hw_actions_construct(struct rte_eth_dev * dev,struct mlx5_hw_q_job * job,const struct mlx5_hw_actions * hw_acts,const uint8_t it_idx,const struct rte_flow_action actions[],struct mlx5dr_rule_action * rule_acts,uint32_t * acts_num)900 flow_hw_actions_construct(struct rte_eth_dev *dev,
901 struct mlx5_hw_q_job *job,
902 const struct mlx5_hw_actions *hw_acts,
903 const uint8_t it_idx,
904 const struct rte_flow_action actions[],
905 struct mlx5dr_rule_action *rule_acts,
906 uint32_t *acts_num)
907 {
908 struct rte_flow_template_table *table = job->flow->table;
909 struct mlx5_action_construct_data *act_data;
910 const struct rte_flow_action *action;
911 const struct rte_flow_action_raw_encap *raw_encap_data;
912 const struct rte_flow_item *enc_item = NULL;
913 uint8_t *buf = job->encap_data;
914 struct rte_flow_attr attr = {
915 .ingress = 1,
916 };
917 uint32_t ft_flag;
918
919 memcpy(rule_acts, hw_acts->rule_acts,
920 sizeof(*rule_acts) * hw_acts->acts_num);
921 *acts_num = hw_acts->acts_num;
922 if (LIST_EMPTY(&hw_acts->act_list))
923 return 0;
924 attr.group = table->grp->group_id;
925 ft_flag = mlx5_hw_act_flag[!!table->grp->group_id][table->type];
926 if (table->type == MLX5DR_TABLE_TYPE_FDB) {
927 attr.transfer = 1;
928 attr.ingress = 1;
929 } else if (table->type == MLX5DR_TABLE_TYPE_NIC_TX) {
930 attr.egress = 1;
931 attr.ingress = 0;
932 } else {
933 attr.ingress = 1;
934 }
935 if (hw_acts->encap_decap && hw_acts->encap_decap->data_size)
936 memcpy(buf, hw_acts->encap_decap->data,
937 hw_acts->encap_decap->data_size);
938 LIST_FOREACH(act_data, &hw_acts->act_list, next) {
939 uint32_t jump_group;
940 uint32_t tag;
941 uint64_t item_flags;
942 struct mlx5_hw_jump_action *jump;
943 struct mlx5_hrxq *hrxq;
944
945 action = &actions[act_data->action_src];
946 MLX5_ASSERT(action->type == RTE_FLOW_ACTION_TYPE_INDIRECT ||
947 (int)action->type == act_data->type);
948 switch (act_data->type) {
949 case RTE_FLOW_ACTION_TYPE_INDIRECT:
950 if (flow_hw_shared_action_construct
951 (dev, action, table, it_idx,
952 &rule_acts[act_data->action_dst]))
953 return -1;
954 break;
955 case RTE_FLOW_ACTION_TYPE_VOID:
956 break;
957 case RTE_FLOW_ACTION_TYPE_MARK:
958 tag = mlx5_flow_mark_set
959 (((const struct rte_flow_action_mark *)
960 (action->conf))->id);
961 rule_acts[act_data->action_dst].tag.value = tag;
962 break;
963 case RTE_FLOW_ACTION_TYPE_JUMP:
964 jump_group = ((const struct rte_flow_action_jump *)
965 action->conf)->group;
966 jump = flow_hw_jump_action_register
967 (dev, &attr, jump_group, NULL);
968 if (!jump)
969 return -1;
970 rule_acts[act_data->action_dst].action =
971 (!!attr.group) ? jump->hws_action : jump->root_action;
972 job->flow->jump = jump;
973 job->flow->fate_type = MLX5_FLOW_FATE_JUMP;
974 break;
975 case RTE_FLOW_ACTION_TYPE_RSS:
976 case RTE_FLOW_ACTION_TYPE_QUEUE:
977 hrxq = flow_hw_tir_action_register(dev,
978 ft_flag,
979 action);
980 if (!hrxq)
981 return -1;
982 rule_acts[act_data->action_dst].action = hrxq->action;
983 job->flow->hrxq = hrxq;
984 job->flow->fate_type = MLX5_FLOW_FATE_QUEUE;
985 break;
986 case MLX5_RTE_FLOW_ACTION_TYPE_RSS:
987 item_flags = table->its[it_idx]->item_flags;
988 if (flow_hw_shared_action_get
989 (dev, act_data, item_flags,
990 &rule_acts[act_data->action_dst]))
991 return -1;
992 break;
993 case RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP:
994 enc_item = ((const struct rte_flow_action_vxlan_encap *)
995 action->conf)->definition;
996 rte_memcpy((void *)&buf[act_data->encap.dst],
997 enc_item[act_data->encap.src].spec,
998 act_data->encap.len);
999 break;
1000 case RTE_FLOW_ACTION_TYPE_NVGRE_ENCAP:
1001 enc_item = ((const struct rte_flow_action_nvgre_encap *)
1002 action->conf)->definition;
1003 rte_memcpy((void *)&buf[act_data->encap.dst],
1004 enc_item[act_data->encap.src].spec,
1005 act_data->encap.len);
1006 break;
1007 case RTE_FLOW_ACTION_TYPE_RAW_ENCAP:
1008 raw_encap_data =
1009 (const struct rte_flow_action_raw_encap *)
1010 action->conf;
1011 rte_memcpy((void *)&buf[act_data->encap.dst],
1012 raw_encap_data->data, act_data->encap.len);
1013 MLX5_ASSERT(raw_encap_data->size ==
1014 act_data->encap.len);
1015 break;
1016 default:
1017 break;
1018 }
1019 }
1020 if (hw_acts->encap_decap) {
1021 rule_acts[hw_acts->encap_decap_pos].reformat.offset =
1022 job->flow->idx - 1;
1023 rule_acts[hw_acts->encap_decap_pos].reformat.data = buf;
1024 }
1025 return 0;
1026 }
1027
1028 /**
1029 * Enqueue HW steering flow creation.
1030 *
1031 * The flow will be applied to the HW only if the postpone bit is not set or
1032 * the extra push function is called.
1033 * The flow creation status should be checked from dequeue result.
1034 *
1035 * @param[in] dev
1036 * Pointer to the rte_eth_dev structure.
1037 * @param[in] queue
1038 * The queue to create the flow.
1039 * @param[in] attr
1040 * Pointer to the flow operation attributes.
1041 * @param[in] items
1042 * Items with flow spec value.
1043 * @param[in] pattern_template_index
1044 * The item pattern flow follows from the table.
1045 * @param[in] actions
1046 * Action with flow spec value.
1047 * @param[in] action_template_index
1048 * The action pattern flow follows from the table.
1049 * @param[in] user_data
1050 * Pointer to the user_data.
1051 * @param[out] error
1052 * Pointer to error structure.
1053 *
1054 * @return
1055 * Flow pointer on success, NULL otherwise and rte_errno is set.
1056 */
1057 static struct rte_flow *
flow_hw_async_flow_create(struct rte_eth_dev * dev,uint32_t queue,const struct rte_flow_op_attr * attr,struct rte_flow_template_table * table,const struct rte_flow_item items[],uint8_t pattern_template_index,const struct rte_flow_action actions[],uint8_t action_template_index,void * user_data,struct rte_flow_error * error)1058 flow_hw_async_flow_create(struct rte_eth_dev *dev,
1059 uint32_t queue,
1060 const struct rte_flow_op_attr *attr,
1061 struct rte_flow_template_table *table,
1062 const struct rte_flow_item items[],
1063 uint8_t pattern_template_index,
1064 const struct rte_flow_action actions[],
1065 uint8_t action_template_index,
1066 void *user_data,
1067 struct rte_flow_error *error)
1068 {
1069 struct mlx5_priv *priv = dev->data->dev_private;
1070 struct mlx5dr_rule_attr rule_attr = {
1071 .queue_id = queue,
1072 .user_data = user_data,
1073 .burst = attr->postpone,
1074 };
1075 struct mlx5dr_rule_action rule_acts[MLX5_HW_MAX_ACTS];
1076 struct mlx5_hw_actions *hw_acts;
1077 struct rte_flow_hw *flow;
1078 struct mlx5_hw_q_job *job;
1079 uint32_t acts_num, flow_idx;
1080 int ret;
1081
1082 if (unlikely(!priv->hw_q[queue].job_idx)) {
1083 rte_errno = ENOMEM;
1084 goto error;
1085 }
1086 flow = mlx5_ipool_zmalloc(table->flow, &flow_idx);
1087 if (!flow)
1088 goto error;
1089 /*
1090 * Set the table here in order to know the destination table
1091 * when free the flow afterwards.
1092 */
1093 flow->table = table;
1094 flow->idx = flow_idx;
1095 job = priv->hw_q[queue].job[--priv->hw_q[queue].job_idx];
1096 /*
1097 * Set the job type here in order to know if the flow memory
1098 * should be freed or not when get the result from dequeue.
1099 */
1100 job->type = MLX5_HW_Q_JOB_TYPE_CREATE;
1101 job->flow = flow;
1102 job->user_data = user_data;
1103 rule_attr.user_data = job;
1104 hw_acts = &table->ats[action_template_index].acts;
1105 /* Construct the flow action array based on the input actions.*/
1106 flow_hw_actions_construct(dev, job, hw_acts, pattern_template_index,
1107 actions, rule_acts, &acts_num);
1108 ret = mlx5dr_rule_create(table->matcher,
1109 pattern_template_index, items,
1110 rule_acts, acts_num,
1111 &rule_attr, &flow->rule);
1112 if (likely(!ret))
1113 return (struct rte_flow *)flow;
1114 /* Flow created fail, return the descriptor and flow memory. */
1115 mlx5_ipool_free(table->flow, flow_idx);
1116 priv->hw_q[queue].job_idx++;
1117 error:
1118 rte_flow_error_set(error, rte_errno,
1119 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
1120 "fail to create rte flow");
1121 return NULL;
1122 }
1123
1124 /**
1125 * Enqueue HW steering flow destruction.
1126 *
1127 * The flow will be applied to the HW only if the postpone bit is not set or
1128 * the extra push function is called.
1129 * The flow destruction status should be checked from dequeue result.
1130 *
1131 * @param[in] dev
1132 * Pointer to the rte_eth_dev structure.
1133 * @param[in] queue
1134 * The queue to destroy the flow.
1135 * @param[in] attr
1136 * Pointer to the flow operation attributes.
1137 * @param[in] flow
1138 * Pointer to the flow to be destroyed.
1139 * @param[in] user_data
1140 * Pointer to the user_data.
1141 * @param[out] error
1142 * Pointer to error structure.
1143 *
1144 * @return
1145 * 0 on success, negative value otherwise and rte_errno is set.
1146 */
1147 static int
flow_hw_async_flow_destroy(struct rte_eth_dev * dev,uint32_t queue,const struct rte_flow_op_attr * attr,struct rte_flow * flow,void * user_data,struct rte_flow_error * error)1148 flow_hw_async_flow_destroy(struct rte_eth_dev *dev,
1149 uint32_t queue,
1150 const struct rte_flow_op_attr *attr,
1151 struct rte_flow *flow,
1152 void *user_data,
1153 struct rte_flow_error *error)
1154 {
1155 struct mlx5_priv *priv = dev->data->dev_private;
1156 struct mlx5dr_rule_attr rule_attr = {
1157 .queue_id = queue,
1158 .user_data = user_data,
1159 .burst = attr->postpone,
1160 };
1161 struct rte_flow_hw *fh = (struct rte_flow_hw *)flow;
1162 struct mlx5_hw_q_job *job;
1163 int ret;
1164
1165 if (unlikely(!priv->hw_q[queue].job_idx)) {
1166 rte_errno = ENOMEM;
1167 goto error;
1168 }
1169 job = priv->hw_q[queue].job[--priv->hw_q[queue].job_idx];
1170 job->type = MLX5_HW_Q_JOB_TYPE_DESTROY;
1171 job->user_data = user_data;
1172 job->flow = fh;
1173 rule_attr.user_data = job;
1174 ret = mlx5dr_rule_destroy(&fh->rule, &rule_attr);
1175 if (likely(!ret))
1176 return 0;
1177 priv->hw_q[queue].job_idx++;
1178 error:
1179 return rte_flow_error_set(error, rte_errno,
1180 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
1181 "fail to create rte flow");
1182 }
1183
1184 /**
1185 * Pull the enqueued flows.
1186 *
1187 * For flows enqueued from creation/destruction, the status should be
1188 * checked from the dequeue result.
1189 *
1190 * @param[in] dev
1191 * Pointer to the rte_eth_dev structure.
1192 * @param[in] queue
1193 * The queue to pull the result.
1194 * @param[in/out] res
1195 * Array to save the results.
1196 * @param[in] n_res
1197 * Available result with the array.
1198 * @param[out] error
1199 * Pointer to error structure.
1200 *
1201 * @return
1202 * Result number on success, negative value otherwise and rte_errno is set.
1203 */
1204 static int
flow_hw_pull(struct rte_eth_dev * dev,uint32_t queue,struct rte_flow_op_result res[],uint16_t n_res,struct rte_flow_error * error)1205 flow_hw_pull(struct rte_eth_dev *dev,
1206 uint32_t queue,
1207 struct rte_flow_op_result res[],
1208 uint16_t n_res,
1209 struct rte_flow_error *error)
1210 {
1211 struct mlx5_priv *priv = dev->data->dev_private;
1212 struct mlx5_hw_q_job *job;
1213 int ret, i;
1214
1215 ret = mlx5dr_send_queue_poll(priv->dr_ctx, queue, res, n_res);
1216 if (ret < 0)
1217 return rte_flow_error_set(error, rte_errno,
1218 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
1219 "fail to query flow queue");
1220 for (i = 0; i < ret; i++) {
1221 job = (struct mlx5_hw_q_job *)res[i].user_data;
1222 /* Restore user data. */
1223 res[i].user_data = job->user_data;
1224 if (job->type == MLX5_HW_Q_JOB_TYPE_DESTROY) {
1225 if (job->flow->fate_type == MLX5_FLOW_FATE_JUMP)
1226 flow_hw_jump_release(dev, job->flow->jump);
1227 else if (job->flow->fate_type == MLX5_FLOW_FATE_QUEUE)
1228 mlx5_hrxq_obj_release(dev, job->flow->hrxq);
1229 mlx5_ipool_free(job->flow->table->flow, job->flow->idx);
1230 }
1231 priv->hw_q[queue].job[priv->hw_q[queue].job_idx++] = job;
1232 }
1233 return ret;
1234 }
1235
1236 /**
1237 * Push the enqueued flows to HW.
1238 *
1239 * Force apply all the enqueued flows to the HW.
1240 *
1241 * @param[in] dev
1242 * Pointer to the rte_eth_dev structure.
1243 * @param[in] queue
1244 * The queue to push the flow.
1245 * @param[out] error
1246 * Pointer to error structure.
1247 *
1248 * @return
1249 * 0 on success, negative value otherwise and rte_errno is set.
1250 */
1251 static int
flow_hw_push(struct rte_eth_dev * dev,uint32_t queue,struct rte_flow_error * error)1252 flow_hw_push(struct rte_eth_dev *dev,
1253 uint32_t queue,
1254 struct rte_flow_error *error)
1255 {
1256 struct mlx5_priv *priv = dev->data->dev_private;
1257 int ret;
1258
1259 ret = mlx5dr_send_queue_action(priv->dr_ctx, queue,
1260 MLX5DR_SEND_QUEUE_ACTION_DRAIN);
1261 if (ret) {
1262 rte_flow_error_set(error, rte_errno,
1263 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
1264 "fail to push flows");
1265 return ret;
1266 }
1267 return 0;
1268 }
1269
1270 /**
1271 * Drain the enqueued flows' completion.
1272 *
1273 * @param[in] dev
1274 * Pointer to the rte_eth_dev structure.
1275 * @param[in] queue
1276 * The queue to pull the flow.
1277 * @param[in] pending_rules
1278 * The pending flow number.
1279 * @param[out] error
1280 * Pointer to error structure.
1281 *
1282 * @return
1283 * 0 on success, negative value otherwise and rte_errno is set.
1284 */
1285 static int
__flow_hw_pull_comp(struct rte_eth_dev * dev,uint32_t queue,uint32_t pending_rules,struct rte_flow_error * error)1286 __flow_hw_pull_comp(struct rte_eth_dev *dev,
1287 uint32_t queue,
1288 uint32_t pending_rules,
1289 struct rte_flow_error *error)
1290 {
1291 struct rte_flow_op_result comp[BURST_THR];
1292 int ret, i, empty_loop = 0;
1293
1294 flow_hw_push(dev, queue, error);
1295 while (pending_rules) {
1296 ret = flow_hw_pull(dev, queue, comp, BURST_THR, error);
1297 if (ret < 0)
1298 return -1;
1299 if (!ret) {
1300 rte_delay_us_sleep(20000);
1301 if (++empty_loop > 5) {
1302 DRV_LOG(WARNING, "No available dequeue, quit.");
1303 break;
1304 }
1305 continue;
1306 }
1307 for (i = 0; i < ret; i++) {
1308 if (comp[i].status == RTE_FLOW_OP_ERROR)
1309 DRV_LOG(WARNING, "Flow flush get error CQE.");
1310 }
1311 if ((uint32_t)ret > pending_rules) {
1312 DRV_LOG(WARNING, "Flow flush get extra CQE.");
1313 return rte_flow_error_set(error, ERANGE,
1314 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
1315 "get extra CQE");
1316 }
1317 pending_rules -= ret;
1318 empty_loop = 0;
1319 }
1320 return 0;
1321 }
1322
1323 /**
1324 * Flush created flows.
1325 *
1326 * @param[in] dev
1327 * Pointer to the rte_eth_dev structure.
1328 * @param[out] error
1329 * Pointer to error structure.
1330 *
1331 * @return
1332 * 0 on success, negative value otherwise and rte_errno is set.
1333 */
1334 int
flow_hw_q_flow_flush(struct rte_eth_dev * dev,struct rte_flow_error * error)1335 flow_hw_q_flow_flush(struct rte_eth_dev *dev,
1336 struct rte_flow_error *error)
1337 {
1338 struct mlx5_priv *priv = dev->data->dev_private;
1339 struct mlx5_hw_q *hw_q;
1340 struct rte_flow_template_table *tbl;
1341 struct rte_flow_hw *flow;
1342 struct rte_flow_op_attr attr = {
1343 .postpone = 0,
1344 };
1345 uint32_t pending_rules = 0;
1346 uint32_t queue;
1347 uint32_t fidx;
1348
1349 /*
1350 * Ensure to push and dequeue all the enqueued flow
1351 * creation/destruction jobs in case user forgot to
1352 * dequeue. Or the enqueued created flows will be
1353 * leaked. The forgotten dequeues would also cause
1354 * flow flush get extra CQEs as expected and pending_rules
1355 * be minus value.
1356 */
1357 for (queue = 0; queue < priv->nb_queue; queue++) {
1358 hw_q = &priv->hw_q[queue];
1359 if (__flow_hw_pull_comp(dev, queue, hw_q->size - hw_q->job_idx,
1360 error))
1361 return -1;
1362 }
1363 /* Flush flow per-table from MLX5_DEFAULT_FLUSH_QUEUE. */
1364 hw_q = &priv->hw_q[MLX5_DEFAULT_FLUSH_QUEUE];
1365 LIST_FOREACH(tbl, &priv->flow_hw_tbl, next) {
1366 MLX5_IPOOL_FOREACH(tbl->flow, fidx, flow) {
1367 if (flow_hw_async_flow_destroy(dev,
1368 MLX5_DEFAULT_FLUSH_QUEUE,
1369 &attr,
1370 (struct rte_flow *)flow,
1371 NULL,
1372 error))
1373 return -1;
1374 pending_rules++;
1375 /* Drain completion with queue size. */
1376 if (pending_rules >= hw_q->size) {
1377 if (__flow_hw_pull_comp(dev,
1378 MLX5_DEFAULT_FLUSH_QUEUE,
1379 pending_rules, error))
1380 return -1;
1381 pending_rules = 0;
1382 }
1383 }
1384 }
1385 /* Drain left completion. */
1386 if (pending_rules &&
1387 __flow_hw_pull_comp(dev, MLX5_DEFAULT_FLUSH_QUEUE, pending_rules,
1388 error))
1389 return -1;
1390 return 0;
1391 }
1392
1393 /**
1394 * Create flow table.
1395 *
1396 * The input item and action templates will be binded to the table.
1397 * Flow memory will also be allocated. Matcher will be created based
1398 * on the item template. Action will be translated to the dedicated
1399 * DR action if possible.
1400 *
1401 * @param[in] dev
1402 * Pointer to the rte_eth_dev structure.
1403 * @param[in] attr
1404 * Pointer to the table attributes.
1405 * @param[in] item_templates
1406 * Item template array to be binded to the table.
1407 * @param[in] nb_item_templates
1408 * Number of item template.
1409 * @param[in] action_templates
1410 * Action template array to be binded to the table.
1411 * @param[in] nb_action_templates
1412 * Number of action template.
1413 * @param[out] error
1414 * Pointer to error structure.
1415 *
1416 * @return
1417 * Table on success, NULL otherwise and rte_errno is set.
1418 */
1419 static struct rte_flow_template_table *
flow_hw_table_create(struct rte_eth_dev * dev,const struct rte_flow_template_table_attr * attr,struct rte_flow_pattern_template * item_templates[],uint8_t nb_item_templates,struct rte_flow_actions_template * action_templates[],uint8_t nb_action_templates,struct rte_flow_error * error)1420 flow_hw_table_create(struct rte_eth_dev *dev,
1421 const struct rte_flow_template_table_attr *attr,
1422 struct rte_flow_pattern_template *item_templates[],
1423 uint8_t nb_item_templates,
1424 struct rte_flow_actions_template *action_templates[],
1425 uint8_t nb_action_templates,
1426 struct rte_flow_error *error)
1427 {
1428 struct mlx5_priv *priv = dev->data->dev_private;
1429 struct mlx5dr_matcher_attr matcher_attr = {0};
1430 struct rte_flow_template_table *tbl = NULL;
1431 struct mlx5_flow_group *grp;
1432 struct mlx5dr_match_template *mt[MLX5_HW_TBL_MAX_ITEM_TEMPLATE];
1433 struct rte_flow_attr flow_attr = attr->flow_attr;
1434 struct mlx5_flow_cb_ctx ctx = {
1435 .dev = dev,
1436 .error = error,
1437 .data = &flow_attr,
1438 };
1439 struct mlx5_indexed_pool_config cfg = {
1440 .size = sizeof(struct rte_flow_hw),
1441 .trunk_size = 1 << 12,
1442 .per_core_cache = 1 << 13,
1443 .need_lock = 1,
1444 .release_mem_en = !!priv->sh->config.reclaim_mode,
1445 .malloc = mlx5_malloc,
1446 .free = mlx5_free,
1447 .type = "mlx5_hw_table_flow",
1448 };
1449 struct mlx5_list_entry *ge;
1450 uint32_t i, max_tpl = MLX5_HW_TBL_MAX_ITEM_TEMPLATE;
1451 uint32_t nb_flows = rte_align32pow2(attr->nb_flows);
1452 int err;
1453
1454 /* HWS layer accepts only 1 item template with root table. */
1455 if (!attr->flow_attr.group)
1456 max_tpl = 1;
1457 cfg.max_idx = nb_flows;
1458 /* For table has very limited flows, disable cache. */
1459 if (nb_flows < cfg.trunk_size) {
1460 cfg.per_core_cache = 0;
1461 cfg.trunk_size = nb_flows;
1462 }
1463 /* Check if we requires too many templates. */
1464 if (nb_item_templates > max_tpl ||
1465 nb_action_templates > MLX5_HW_TBL_MAX_ACTION_TEMPLATE) {
1466 rte_errno = EINVAL;
1467 goto error;
1468 }
1469 /* Allocate the table memory. */
1470 tbl = mlx5_malloc(MLX5_MEM_ZERO, sizeof(*tbl), 0, rte_socket_id());
1471 if (!tbl)
1472 goto error;
1473 /* Allocate flow indexed pool. */
1474 tbl->flow = mlx5_ipool_create(&cfg);
1475 if (!tbl->flow)
1476 goto error;
1477 /* Register the flow group. */
1478 ge = mlx5_hlist_register(priv->sh->groups, attr->flow_attr.group, &ctx);
1479 if (!ge)
1480 goto error;
1481 grp = container_of(ge, struct mlx5_flow_group, entry);
1482 tbl->grp = grp;
1483 /* Prepare matcher information. */
1484 matcher_attr.priority = attr->flow_attr.priority;
1485 matcher_attr.mode = MLX5DR_MATCHER_RESOURCE_MODE_RULE;
1486 matcher_attr.rule.num_log = rte_log2_u32(nb_flows);
1487 /* Build the item template. */
1488 for (i = 0; i < nb_item_templates; i++) {
1489 uint32_t ret;
1490
1491 ret = __atomic_add_fetch(&item_templates[i]->refcnt, 1,
1492 __ATOMIC_RELAXED);
1493 if (ret <= 1) {
1494 rte_errno = EINVAL;
1495 goto it_error;
1496 }
1497 mt[i] = item_templates[i]->mt;
1498 tbl->its[i] = item_templates[i];
1499 }
1500 tbl->matcher = mlx5dr_matcher_create
1501 (tbl->grp->tbl, mt, nb_item_templates, &matcher_attr);
1502 if (!tbl->matcher)
1503 goto it_error;
1504 tbl->nb_item_templates = nb_item_templates;
1505 /* Build the action template. */
1506 for (i = 0; i < nb_action_templates; i++) {
1507 uint32_t ret;
1508
1509 ret = __atomic_add_fetch(&action_templates[i]->refcnt, 1,
1510 __ATOMIC_RELAXED);
1511 if (ret <= 1) {
1512 rte_errno = EINVAL;
1513 goto at_error;
1514 }
1515 LIST_INIT(&tbl->ats[i].acts.act_list);
1516 err = flow_hw_actions_translate(dev, attr,
1517 &tbl->ats[i].acts,
1518 action_templates[i], error);
1519 if (err) {
1520 i++;
1521 goto at_error;
1522 }
1523 tbl->ats[i].action_template = action_templates[i];
1524 }
1525 tbl->nb_action_templates = nb_action_templates;
1526 tbl->type = attr->flow_attr.transfer ? MLX5DR_TABLE_TYPE_FDB :
1527 (attr->flow_attr.egress ? MLX5DR_TABLE_TYPE_NIC_TX :
1528 MLX5DR_TABLE_TYPE_NIC_RX);
1529 LIST_INSERT_HEAD(&priv->flow_hw_tbl, tbl, next);
1530 return tbl;
1531 at_error:
1532 while (i--) {
1533 __flow_hw_action_template_destroy(dev, &tbl->ats[i].acts);
1534 __atomic_sub_fetch(&action_templates[i]->refcnt,
1535 1, __ATOMIC_RELAXED);
1536 }
1537 i = nb_item_templates;
1538 it_error:
1539 while (i--)
1540 __atomic_sub_fetch(&item_templates[i]->refcnt,
1541 1, __ATOMIC_RELAXED);
1542 mlx5dr_matcher_destroy(tbl->matcher);
1543 error:
1544 err = rte_errno;
1545 if (tbl) {
1546 if (tbl->grp)
1547 mlx5_hlist_unregister(priv->sh->groups,
1548 &tbl->grp->entry);
1549 if (tbl->flow)
1550 mlx5_ipool_destroy(tbl->flow);
1551 mlx5_free(tbl);
1552 }
1553 rte_flow_error_set(error, err,
1554 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
1555 "fail to create rte table");
1556 return NULL;
1557 }
1558
1559 /**
1560 * Destroy flow table.
1561 *
1562 * @param[in] dev
1563 * Pointer to the rte_eth_dev structure.
1564 * @param[in] table
1565 * Pointer to the table to be destroyed.
1566 * @param[out] error
1567 * Pointer to error structure.
1568 *
1569 * @return
1570 * 0 on success, a negative errno value otherwise and rte_errno is set.
1571 */
1572 static int
flow_hw_table_destroy(struct rte_eth_dev * dev,struct rte_flow_template_table * table,struct rte_flow_error * error)1573 flow_hw_table_destroy(struct rte_eth_dev *dev,
1574 struct rte_flow_template_table *table,
1575 struct rte_flow_error *error)
1576 {
1577 struct mlx5_priv *priv = dev->data->dev_private;
1578 int i;
1579
1580 if (table->refcnt) {
1581 DRV_LOG(WARNING, "Table %p is still in using.", (void *)table);
1582 return rte_flow_error_set(error, EBUSY,
1583 RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1584 NULL,
1585 "table in using");
1586 }
1587 LIST_REMOVE(table, next);
1588 for (i = 0; i < table->nb_item_templates; i++)
1589 __atomic_sub_fetch(&table->its[i]->refcnt,
1590 1, __ATOMIC_RELAXED);
1591 for (i = 0; i < table->nb_action_templates; i++) {
1592 if (table->ats[i].acts.mark)
1593 flow_hw_rxq_flag_set(dev, false);
1594 __flow_hw_action_template_destroy(dev, &table->ats[i].acts);
1595 __atomic_sub_fetch(&table->ats[i].action_template->refcnt,
1596 1, __ATOMIC_RELAXED);
1597 }
1598 mlx5dr_matcher_destroy(table->matcher);
1599 mlx5_hlist_unregister(priv->sh->groups, &table->grp->entry);
1600 mlx5_ipool_destroy(table->flow);
1601 mlx5_free(table);
1602 return 0;
1603 }
1604
1605 /**
1606 * Create flow action template.
1607 *
1608 * @param[in] dev
1609 * Pointer to the rte_eth_dev structure.
1610 * @param[in] attr
1611 * Pointer to the action template attributes.
1612 * @param[in] actions
1613 * Associated actions (list terminated by the END action).
1614 * @param[in] masks
1615 * List of actions that marks which of the action's member is constant.
1616 * @param[out] error
1617 * Pointer to error structure.
1618 *
1619 * @return
1620 * Action template pointer on success, NULL otherwise and rte_errno is set.
1621 */
1622 static struct rte_flow_actions_template *
flow_hw_actions_template_create(struct rte_eth_dev * dev,const struct rte_flow_actions_template_attr * attr,const struct rte_flow_action actions[],const struct rte_flow_action masks[],struct rte_flow_error * error)1623 flow_hw_actions_template_create(struct rte_eth_dev *dev,
1624 const struct rte_flow_actions_template_attr *attr,
1625 const struct rte_flow_action actions[],
1626 const struct rte_flow_action masks[],
1627 struct rte_flow_error *error)
1628 {
1629 struct mlx5_priv *priv = dev->data->dev_private;
1630 int len, act_len, mask_len, i;
1631 struct rte_flow_actions_template *at;
1632
1633 act_len = rte_flow_conv(RTE_FLOW_CONV_OP_ACTIONS,
1634 NULL, 0, actions, error);
1635 if (act_len <= 0)
1636 return NULL;
1637 len = RTE_ALIGN(act_len, 16);
1638 mask_len = rte_flow_conv(RTE_FLOW_CONV_OP_ACTIONS,
1639 NULL, 0, masks, error);
1640 if (mask_len <= 0)
1641 return NULL;
1642 len += RTE_ALIGN(mask_len, 16);
1643 at = mlx5_malloc(MLX5_MEM_ZERO, len + sizeof(*at), 64, rte_socket_id());
1644 if (!at) {
1645 rte_flow_error_set(error, ENOMEM,
1646 RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1647 NULL,
1648 "cannot allocate action template");
1649 return NULL;
1650 }
1651 at->attr = *attr;
1652 at->actions = (struct rte_flow_action *)(at + 1);
1653 act_len = rte_flow_conv(RTE_FLOW_CONV_OP_ACTIONS, at->actions, len,
1654 actions, error);
1655 if (act_len <= 0)
1656 goto error;
1657 at->masks = (struct rte_flow_action *)
1658 (((uint8_t *)at->actions) + act_len);
1659 mask_len = rte_flow_conv(RTE_FLOW_CONV_OP_ACTIONS, at->masks,
1660 len - act_len, masks, error);
1661 if (mask_len <= 0)
1662 goto error;
1663 /*
1664 * mlx5 PMD hacks indirect action index directly to the action conf.
1665 * The rte_flow_conv() function copies the content from conf pointer.
1666 * Need to restore the indirect action index from action conf here.
1667 */
1668 for (i = 0; actions->type != RTE_FLOW_ACTION_TYPE_END;
1669 actions++, masks++, i++) {
1670 if (actions->type == RTE_FLOW_ACTION_TYPE_INDIRECT) {
1671 at->actions[i].conf = actions->conf;
1672 at->masks[i].conf = masks->conf;
1673 }
1674 }
1675 __atomic_fetch_add(&at->refcnt, 1, __ATOMIC_RELAXED);
1676 LIST_INSERT_HEAD(&priv->flow_hw_at, at, next);
1677 return at;
1678 error:
1679 mlx5_free(at);
1680 return NULL;
1681 }
1682
1683 /**
1684 * Destroy flow action template.
1685 *
1686 * @param[in] dev
1687 * Pointer to the rte_eth_dev structure.
1688 * @param[in] template
1689 * Pointer to the action template to be destroyed.
1690 * @param[out] error
1691 * Pointer to error structure.
1692 *
1693 * @return
1694 * 0 on success, a negative errno value otherwise and rte_errno is set.
1695 */
1696 static int
flow_hw_actions_template_destroy(struct rte_eth_dev * dev __rte_unused,struct rte_flow_actions_template * template,struct rte_flow_error * error __rte_unused)1697 flow_hw_actions_template_destroy(struct rte_eth_dev *dev __rte_unused,
1698 struct rte_flow_actions_template *template,
1699 struct rte_flow_error *error __rte_unused)
1700 {
1701 if (__atomic_load_n(&template->refcnt, __ATOMIC_RELAXED) > 1) {
1702 DRV_LOG(WARNING, "Action template %p is still in use.",
1703 (void *)template);
1704 return rte_flow_error_set(error, EBUSY,
1705 RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1706 NULL,
1707 "action template in using");
1708 }
1709 LIST_REMOVE(template, next);
1710 mlx5_free(template);
1711 return 0;
1712 }
1713
1714 /**
1715 * Create flow item template.
1716 *
1717 * @param[in] dev
1718 * Pointer to the rte_eth_dev structure.
1719 * @param[in] attr
1720 * Pointer to the item template attributes.
1721 * @param[in] items
1722 * The template item pattern.
1723 * @param[out] error
1724 * Pointer to error structure.
1725 *
1726 * @return
1727 * Item template pointer on success, NULL otherwise and rte_errno is set.
1728 */
1729 static struct rte_flow_pattern_template *
flow_hw_pattern_template_create(struct rte_eth_dev * dev,const struct rte_flow_pattern_template_attr * attr,const struct rte_flow_item items[],struct rte_flow_error * error)1730 flow_hw_pattern_template_create(struct rte_eth_dev *dev,
1731 const struct rte_flow_pattern_template_attr *attr,
1732 const struct rte_flow_item items[],
1733 struct rte_flow_error *error)
1734 {
1735 struct mlx5_priv *priv = dev->data->dev_private;
1736 struct rte_flow_pattern_template *it;
1737
1738 it = mlx5_malloc(MLX5_MEM_ZERO, sizeof(*it), 0, rte_socket_id());
1739 if (!it) {
1740 rte_flow_error_set(error, ENOMEM,
1741 RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1742 NULL,
1743 "cannot allocate item template");
1744 return NULL;
1745 }
1746 it->attr = *attr;
1747 it->mt = mlx5dr_match_template_create(items, attr->relaxed_matching);
1748 if (!it->mt) {
1749 mlx5_free(it);
1750 rte_flow_error_set(error, rte_errno,
1751 RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1752 NULL,
1753 "cannot create match template");
1754 return NULL;
1755 }
1756 it->item_flags = flow_hw_rss_item_flags_get(items);
1757 __atomic_fetch_add(&it->refcnt, 1, __ATOMIC_RELAXED);
1758 LIST_INSERT_HEAD(&priv->flow_hw_itt, it, next);
1759 return it;
1760 }
1761
1762 /**
1763 * Destroy flow item template.
1764 *
1765 * @param[in] dev
1766 * Pointer to the rte_eth_dev structure.
1767 * @param[in] template
1768 * Pointer to the item template to be destroyed.
1769 * @param[out] error
1770 * Pointer to error structure.
1771 *
1772 * @return
1773 * 0 on success, a negative errno value otherwise and rte_errno is set.
1774 */
1775 static int
flow_hw_pattern_template_destroy(struct rte_eth_dev * dev __rte_unused,struct rte_flow_pattern_template * template,struct rte_flow_error * error __rte_unused)1776 flow_hw_pattern_template_destroy(struct rte_eth_dev *dev __rte_unused,
1777 struct rte_flow_pattern_template *template,
1778 struct rte_flow_error *error __rte_unused)
1779 {
1780 if (__atomic_load_n(&template->refcnt, __ATOMIC_RELAXED) > 1) {
1781 DRV_LOG(WARNING, "Item template %p is still in use.",
1782 (void *)template);
1783 return rte_flow_error_set(error, EBUSY,
1784 RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1785 NULL,
1786 "item template in using");
1787 }
1788 LIST_REMOVE(template, next);
1789 claim_zero(mlx5dr_match_template_destroy(template->mt));
1790 mlx5_free(template);
1791 return 0;
1792 }
1793
1794 /*
1795 * Get information about HWS pre-configurable resources.
1796 *
1797 * @param[in] dev
1798 * Pointer to the rte_eth_dev structure.
1799 * @param[out] port_info
1800 * Pointer to port information.
1801 * @param[out] queue_info
1802 * Pointer to queue information.
1803 * @param[out] error
1804 * Pointer to error structure.
1805 *
1806 * @return
1807 * 0 on success, a negative errno value otherwise and rte_errno is set.
1808 */
1809 static int
flow_hw_info_get(struct rte_eth_dev * dev __rte_unused,struct rte_flow_port_info * port_info __rte_unused,struct rte_flow_queue_info * queue_info __rte_unused,struct rte_flow_error * error __rte_unused)1810 flow_hw_info_get(struct rte_eth_dev *dev __rte_unused,
1811 struct rte_flow_port_info *port_info __rte_unused,
1812 struct rte_flow_queue_info *queue_info __rte_unused,
1813 struct rte_flow_error *error __rte_unused)
1814 {
1815 /* Nothing to be updated currently. */
1816 memset(port_info, 0, sizeof(*port_info));
1817 /* Queue size is unlimited from low-level. */
1818 queue_info->max_size = UINT32_MAX;
1819 return 0;
1820 }
1821
1822 /**
1823 * Create group callback.
1824 *
1825 * @param[in] tool_ctx
1826 * Pointer to the hash list related context.
1827 * @param[in] cb_ctx
1828 * Pointer to the group creation context.
1829 *
1830 * @return
1831 * Group entry on success, NULL otherwise and rte_errno is set.
1832 */
1833 struct mlx5_list_entry *
flow_hw_grp_create_cb(void * tool_ctx,void * cb_ctx)1834 flow_hw_grp_create_cb(void *tool_ctx, void *cb_ctx)
1835 {
1836 struct mlx5_dev_ctx_shared *sh = tool_ctx;
1837 struct mlx5_flow_cb_ctx *ctx = cb_ctx;
1838 struct rte_eth_dev *dev = ctx->dev;
1839 struct rte_flow_attr *attr = (struct rte_flow_attr *)ctx->data;
1840 struct mlx5_priv *priv = dev->data->dev_private;
1841 struct mlx5dr_table_attr dr_tbl_attr = {0};
1842 struct rte_flow_error *error = ctx->error;
1843 struct mlx5_flow_group *grp_data;
1844 struct mlx5dr_table *tbl = NULL;
1845 struct mlx5dr_action *jump;
1846 uint32_t idx = 0;
1847
1848 grp_data = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_HW_GRP], &idx);
1849 if (!grp_data) {
1850 rte_flow_error_set(error, ENOMEM,
1851 RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1852 NULL,
1853 "cannot allocate flow table data entry");
1854 return NULL;
1855 }
1856 dr_tbl_attr.level = attr->group;
1857 if (attr->transfer)
1858 dr_tbl_attr.type = MLX5DR_TABLE_TYPE_FDB;
1859 else if (attr->egress)
1860 dr_tbl_attr.type = MLX5DR_TABLE_TYPE_NIC_TX;
1861 else
1862 dr_tbl_attr.type = MLX5DR_TABLE_TYPE_NIC_RX;
1863 tbl = mlx5dr_table_create(priv->dr_ctx, &dr_tbl_attr);
1864 if (!tbl)
1865 goto error;
1866 grp_data->tbl = tbl;
1867 if (attr->group) {
1868 /* Jump action be used by non-root table. */
1869 jump = mlx5dr_action_create_dest_table
1870 (priv->dr_ctx, tbl,
1871 mlx5_hw_act_flag[!!attr->group][dr_tbl_attr.type]);
1872 if (!jump)
1873 goto error;
1874 grp_data->jump.hws_action = jump;
1875 /* Jump action be used by root table. */
1876 jump = mlx5dr_action_create_dest_table
1877 (priv->dr_ctx, tbl,
1878 mlx5_hw_act_flag[MLX5_HW_ACTION_FLAG_ROOT]
1879 [dr_tbl_attr.type]);
1880 if (!jump)
1881 goto error;
1882 grp_data->jump.root_action = jump;
1883 }
1884 grp_data->idx = idx;
1885 grp_data->group_id = attr->group;
1886 grp_data->type = dr_tbl_attr.type;
1887 return &grp_data->entry;
1888 error:
1889 if (grp_data->jump.root_action)
1890 mlx5dr_action_destroy(grp_data->jump.root_action);
1891 if (grp_data->jump.hws_action)
1892 mlx5dr_action_destroy(grp_data->jump.hws_action);
1893 if (tbl)
1894 mlx5dr_table_destroy(tbl);
1895 if (idx)
1896 mlx5_ipool_free(sh->ipool[MLX5_IPOOL_HW_GRP], idx);
1897 rte_flow_error_set(error, ENOMEM,
1898 RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1899 NULL,
1900 "cannot allocate flow dr table");
1901 return NULL;
1902 }
1903
1904 /**
1905 * Remove group callback.
1906 *
1907 * @param[in] tool_ctx
1908 * Pointer to the hash list related context.
1909 * @param[in] entry
1910 * Pointer to the entry to be removed.
1911 */
1912 void
flow_hw_grp_remove_cb(void * tool_ctx,struct mlx5_list_entry * entry)1913 flow_hw_grp_remove_cb(void *tool_ctx, struct mlx5_list_entry *entry)
1914 {
1915 struct mlx5_dev_ctx_shared *sh = tool_ctx;
1916 struct mlx5_flow_group *grp_data =
1917 container_of(entry, struct mlx5_flow_group, entry);
1918
1919 MLX5_ASSERT(entry && sh);
1920 /* To use the wrapper glue functions instead. */
1921 if (grp_data->jump.hws_action)
1922 mlx5dr_action_destroy(grp_data->jump.hws_action);
1923 if (grp_data->jump.root_action)
1924 mlx5dr_action_destroy(grp_data->jump.root_action);
1925 mlx5dr_table_destroy(grp_data->tbl);
1926 mlx5_ipool_free(sh->ipool[MLX5_IPOOL_HW_GRP], grp_data->idx);
1927 }
1928
1929 /**
1930 * Match group callback.
1931 *
1932 * @param[in] tool_ctx
1933 * Pointer to the hash list related context.
1934 * @param[in] entry
1935 * Pointer to the group to be matched.
1936 * @param[in] cb_ctx
1937 * Pointer to the group matching context.
1938 *
1939 * @return
1940 * 0 on matched, 1 on miss matched.
1941 */
1942 int
flow_hw_grp_match_cb(void * tool_ctx __rte_unused,struct mlx5_list_entry * entry,void * cb_ctx)1943 flow_hw_grp_match_cb(void *tool_ctx __rte_unused, struct mlx5_list_entry *entry,
1944 void *cb_ctx)
1945 {
1946 struct mlx5_flow_cb_ctx *ctx = cb_ctx;
1947 struct mlx5_flow_group *grp_data =
1948 container_of(entry, struct mlx5_flow_group, entry);
1949 struct rte_flow_attr *attr =
1950 (struct rte_flow_attr *)ctx->data;
1951
1952 return (grp_data->group_id != attr->group) ||
1953 ((grp_data->type != MLX5DR_TABLE_TYPE_FDB) &&
1954 attr->transfer) ||
1955 ((grp_data->type != MLX5DR_TABLE_TYPE_NIC_TX) &&
1956 attr->egress) ||
1957 ((grp_data->type != MLX5DR_TABLE_TYPE_NIC_RX) &&
1958 attr->ingress);
1959 }
1960
1961 /**
1962 * Clone group entry callback.
1963 *
1964 * @param[in] tool_ctx
1965 * Pointer to the hash list related context.
1966 * @param[in] entry
1967 * Pointer to the group to be matched.
1968 * @param[in] cb_ctx
1969 * Pointer to the group matching context.
1970 *
1971 * @return
1972 * 0 on matched, 1 on miss matched.
1973 */
1974 struct mlx5_list_entry *
flow_hw_grp_clone_cb(void * tool_ctx,struct mlx5_list_entry * oentry,void * cb_ctx)1975 flow_hw_grp_clone_cb(void *tool_ctx, struct mlx5_list_entry *oentry,
1976 void *cb_ctx)
1977 {
1978 struct mlx5_dev_ctx_shared *sh = tool_ctx;
1979 struct mlx5_flow_cb_ctx *ctx = cb_ctx;
1980 struct mlx5_flow_group *grp_data;
1981 struct rte_flow_error *error = ctx->error;
1982 uint32_t idx = 0;
1983
1984 grp_data = mlx5_ipool_malloc(sh->ipool[MLX5_IPOOL_HW_GRP], &idx);
1985 if (!grp_data) {
1986 rte_flow_error_set(error, ENOMEM,
1987 RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1988 NULL,
1989 "cannot allocate flow table data entry");
1990 return NULL;
1991 }
1992 memcpy(grp_data, oentry, sizeof(*grp_data));
1993 grp_data->idx = idx;
1994 return &grp_data->entry;
1995 }
1996
1997 /**
1998 * Free cloned group entry callback.
1999 *
2000 * @param[in] tool_ctx
2001 * Pointer to the hash list related context.
2002 * @param[in] entry
2003 * Pointer to the group to be freed.
2004 */
2005 void
flow_hw_grp_clone_free_cb(void * tool_ctx,struct mlx5_list_entry * entry)2006 flow_hw_grp_clone_free_cb(void *tool_ctx, struct mlx5_list_entry *entry)
2007 {
2008 struct mlx5_dev_ctx_shared *sh = tool_ctx;
2009 struct mlx5_flow_group *grp_data =
2010 container_of(entry, struct mlx5_flow_group, entry);
2011
2012 mlx5_ipool_free(sh->ipool[MLX5_IPOOL_HW_GRP], grp_data->idx);
2013 }
2014
2015 /**
2016 * Configure port HWS resources.
2017 *
2018 * @param[in] dev
2019 * Pointer to the rte_eth_dev structure.
2020 * @param[in] port_attr
2021 * Port configuration attributes.
2022 * @param[in] nb_queue
2023 * Number of queue.
2024 * @param[in] queue_attr
2025 * Array that holds attributes for each flow queue.
2026 * @param[out] error
2027 * Pointer to error structure.
2028 *
2029 * @return
2030 * 0 on success, a negative errno value otherwise and rte_errno is set.
2031 */
2032
2033 static int
flow_hw_configure(struct rte_eth_dev * dev,const struct rte_flow_port_attr * port_attr,uint16_t nb_queue,const struct rte_flow_queue_attr * queue_attr[],struct rte_flow_error * error)2034 flow_hw_configure(struct rte_eth_dev *dev,
2035 const struct rte_flow_port_attr *port_attr,
2036 uint16_t nb_queue,
2037 const struct rte_flow_queue_attr *queue_attr[],
2038 struct rte_flow_error *error)
2039 {
2040 struct mlx5_priv *priv = dev->data->dev_private;
2041 struct mlx5dr_context *dr_ctx = NULL;
2042 struct mlx5dr_context_attr dr_ctx_attr = {0};
2043 struct mlx5_hw_q *hw_q;
2044 struct mlx5_hw_q_job *job = NULL;
2045 uint32_t mem_size, i, j;
2046 struct mlx5_indexed_pool_config cfg = {
2047 .size = sizeof(struct rte_flow_hw),
2048 .trunk_size = 4096,
2049 .need_lock = 1,
2050 .release_mem_en = !!priv->sh->config.reclaim_mode,
2051 .malloc = mlx5_malloc,
2052 .free = mlx5_free,
2053 .type = "mlx5_hw_action_construct_data",
2054 };
2055
2056 if (!port_attr || !nb_queue || !queue_attr) {
2057 rte_errno = EINVAL;
2058 goto err;
2059 }
2060 /* In case re-configuring, release existing context at first. */
2061 if (priv->dr_ctx) {
2062 /* */
2063 for (i = 0; i < nb_queue; i++) {
2064 hw_q = &priv->hw_q[i];
2065 /* Make sure all queues are empty. */
2066 if (hw_q->size != hw_q->job_idx) {
2067 rte_errno = EBUSY;
2068 goto err;
2069 }
2070 }
2071 flow_hw_resource_release(dev);
2072 }
2073 priv->acts_ipool = mlx5_ipool_create(&cfg);
2074 if (!priv->acts_ipool)
2075 goto err;
2076 /* Allocate the queue job descriptor LIFO. */
2077 mem_size = sizeof(priv->hw_q[0]) * nb_queue;
2078 for (i = 0; i < nb_queue; i++) {
2079 /*
2080 * Check if the queues' size are all the same as the
2081 * limitation from HWS layer.
2082 */
2083 if (queue_attr[i]->size != queue_attr[0]->size) {
2084 rte_errno = EINVAL;
2085 goto err;
2086 }
2087 mem_size += (sizeof(struct mlx5_hw_q_job *) +
2088 sizeof(uint8_t) * MLX5_ENCAP_MAX_LEN +
2089 sizeof(struct mlx5_hw_q_job)) *
2090 queue_attr[0]->size;
2091 }
2092 priv->hw_q = mlx5_malloc(MLX5_MEM_ZERO, mem_size,
2093 64, SOCKET_ID_ANY);
2094 if (!priv->hw_q) {
2095 rte_errno = ENOMEM;
2096 goto err;
2097 }
2098 for (i = 0; i < nb_queue; i++) {
2099 uint8_t *encap = NULL;
2100
2101 priv->hw_q[i].job_idx = queue_attr[i]->size;
2102 priv->hw_q[i].size = queue_attr[i]->size;
2103 if (i == 0)
2104 priv->hw_q[i].job = (struct mlx5_hw_q_job **)
2105 &priv->hw_q[nb_queue];
2106 else
2107 priv->hw_q[i].job = (struct mlx5_hw_q_job **)
2108 &job[queue_attr[i - 1]->size];
2109 job = (struct mlx5_hw_q_job *)
2110 &priv->hw_q[i].job[queue_attr[i]->size];
2111 encap = (uint8_t *)&job[queue_attr[i]->size];
2112 for (j = 0; j < queue_attr[i]->size; j++) {
2113 job[j].encap_data = &encap[j * MLX5_ENCAP_MAX_LEN];
2114 priv->hw_q[i].job[j] = &job[j];
2115 }
2116 }
2117 dr_ctx_attr.pd = priv->sh->cdev->pd;
2118 dr_ctx_attr.queues = nb_queue;
2119 /* Queue size should all be the same. Take the first one. */
2120 dr_ctx_attr.queue_size = queue_attr[0]->size;
2121 dr_ctx = mlx5dr_context_open(priv->sh->cdev->ctx, &dr_ctx_attr);
2122 /* rte_errno has been updated by HWS layer. */
2123 if (!dr_ctx)
2124 goto err;
2125 priv->dr_ctx = dr_ctx;
2126 priv->nb_queue = nb_queue;
2127 /* Add global actions. */
2128 for (i = 0; i < MLX5_HW_ACTION_FLAG_MAX; i++) {
2129 for (j = 0; j < MLX5DR_TABLE_TYPE_MAX; j++) {
2130 priv->hw_drop[i][j] = mlx5dr_action_create_dest_drop
2131 (priv->dr_ctx, mlx5_hw_act_flag[i][j]);
2132 if (!priv->hw_drop[i][j])
2133 goto err;
2134 }
2135 priv->hw_tag[i] = mlx5dr_action_create_tag
2136 (priv->dr_ctx, mlx5_hw_act_flag[i][0]);
2137 if (!priv->hw_tag[i])
2138 goto err;
2139 }
2140 return 0;
2141 err:
2142 for (i = 0; i < MLX5_HW_ACTION_FLAG_MAX; i++) {
2143 for (j = 0; j < MLX5DR_TABLE_TYPE_MAX; j++) {
2144 if (priv->hw_drop[i][j])
2145 mlx5dr_action_destroy(priv->hw_drop[i][j]);
2146 }
2147 if (priv->hw_tag[i])
2148 mlx5dr_action_destroy(priv->hw_tag[i]);
2149 }
2150 if (dr_ctx)
2151 claim_zero(mlx5dr_context_close(dr_ctx));
2152 mlx5_free(priv->hw_q);
2153 priv->hw_q = NULL;
2154 if (priv->acts_ipool) {
2155 mlx5_ipool_destroy(priv->acts_ipool);
2156 priv->acts_ipool = NULL;
2157 }
2158 return rte_flow_error_set(error, rte_errno,
2159 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
2160 "fail to configure port");
2161 }
2162
2163 /**
2164 * Release HWS resources.
2165 *
2166 * @param[in] dev
2167 * Pointer to the rte_eth_dev structure.
2168 */
2169 void
flow_hw_resource_release(struct rte_eth_dev * dev)2170 flow_hw_resource_release(struct rte_eth_dev *dev)
2171 {
2172 struct mlx5_priv *priv = dev->data->dev_private;
2173 struct rte_flow_template_table *tbl;
2174 struct rte_flow_pattern_template *it;
2175 struct rte_flow_actions_template *at;
2176 int i, j;
2177
2178 if (!priv->dr_ctx)
2179 return;
2180 while (!LIST_EMPTY(&priv->flow_hw_tbl)) {
2181 tbl = LIST_FIRST(&priv->flow_hw_tbl);
2182 flow_hw_table_destroy(dev, tbl, NULL);
2183 }
2184 while (!LIST_EMPTY(&priv->flow_hw_itt)) {
2185 it = LIST_FIRST(&priv->flow_hw_itt);
2186 flow_hw_pattern_template_destroy(dev, it, NULL);
2187 }
2188 while (!LIST_EMPTY(&priv->flow_hw_at)) {
2189 at = LIST_FIRST(&priv->flow_hw_at);
2190 flow_hw_actions_template_destroy(dev, at, NULL);
2191 }
2192 for (i = 0; i < MLX5_HW_ACTION_FLAG_MAX; i++) {
2193 for (j = 0; j < MLX5DR_TABLE_TYPE_MAX; j++) {
2194 if (priv->hw_drop[i][j])
2195 mlx5dr_action_destroy(priv->hw_drop[i][j]);
2196 }
2197 if (priv->hw_tag[i])
2198 mlx5dr_action_destroy(priv->hw_tag[i]);
2199 }
2200 if (priv->acts_ipool) {
2201 mlx5_ipool_destroy(priv->acts_ipool);
2202 priv->acts_ipool = NULL;
2203 }
2204 mlx5_free(priv->hw_q);
2205 priv->hw_q = NULL;
2206 claim_zero(mlx5dr_context_close(priv->dr_ctx));
2207 priv->dr_ctx = NULL;
2208 priv->nb_queue = 0;
2209 }
2210
2211 /**
2212 * Create shared action.
2213 *
2214 * @param[in] dev
2215 * Pointer to the rte_eth_dev structure.
2216 * @param[in] queue
2217 * Which queue to be used..
2218 * @param[in] attr
2219 * Operation attribute.
2220 * @param[in] conf
2221 * Indirect action configuration.
2222 * @param[in] action
2223 * rte_flow action detail.
2224 * @param[in] user_data
2225 * Pointer to the user_data.
2226 * @param[out] error
2227 * Pointer to error structure.
2228 *
2229 * @return
2230 * Action handle on success, NULL otherwise and rte_errno is set.
2231 */
2232 static struct rte_flow_action_handle *
flow_hw_action_handle_create(struct rte_eth_dev * dev,uint32_t queue,const struct rte_flow_op_attr * attr,const struct rte_flow_indir_action_conf * conf,const struct rte_flow_action * action,void * user_data,struct rte_flow_error * error)2233 flow_hw_action_handle_create(struct rte_eth_dev *dev, uint32_t queue,
2234 const struct rte_flow_op_attr *attr,
2235 const struct rte_flow_indir_action_conf *conf,
2236 const struct rte_flow_action *action,
2237 void *user_data,
2238 struct rte_flow_error *error)
2239 {
2240 RTE_SET_USED(queue);
2241 RTE_SET_USED(attr);
2242 RTE_SET_USED(user_data);
2243 return flow_dv_action_create(dev, conf, action, error);
2244 }
2245
2246 /**
2247 * Update shared action.
2248 *
2249 * @param[in] dev
2250 * Pointer to the rte_eth_dev structure.
2251 * @param[in] queue
2252 * Which queue to be used..
2253 * @param[in] attr
2254 * Operation attribute.
2255 * @param[in] handle
2256 * Action handle to be updated.
2257 * @param[in] update
2258 * Update value.
2259 * @param[in] user_data
2260 * Pointer to the user_data.
2261 * @param[out] error
2262 * Pointer to error structure.
2263 *
2264 * @return
2265 * 0 on success, negative value otherwise and rte_errno is set.
2266 */
2267 static int
flow_hw_action_handle_update(struct rte_eth_dev * dev,uint32_t queue,const struct rte_flow_op_attr * attr,struct rte_flow_action_handle * handle,const void * update,void * user_data,struct rte_flow_error * error)2268 flow_hw_action_handle_update(struct rte_eth_dev *dev, uint32_t queue,
2269 const struct rte_flow_op_attr *attr,
2270 struct rte_flow_action_handle *handle,
2271 const void *update,
2272 void *user_data,
2273 struct rte_flow_error *error)
2274 {
2275 RTE_SET_USED(queue);
2276 RTE_SET_USED(attr);
2277 RTE_SET_USED(user_data);
2278 return flow_dv_action_update(dev, handle, update, error);
2279 }
2280
2281 /**
2282 * Destroy shared action.
2283 *
2284 * @param[in] dev
2285 * Pointer to the rte_eth_dev structure.
2286 * @param[in] queue
2287 * Which queue to be used..
2288 * @param[in] attr
2289 * Operation attribute.
2290 * @param[in] handle
2291 * Action handle to be destroyed.
2292 * @param[in] user_data
2293 * Pointer to the user_data.
2294 * @param[out] error
2295 * Pointer to error structure.
2296 *
2297 * @return
2298 * 0 on success, negative value otherwise and rte_errno is set.
2299 */
2300 static int
flow_hw_action_handle_destroy(struct rte_eth_dev * dev,uint32_t queue,const struct rte_flow_op_attr * attr,struct rte_flow_action_handle * handle,void * user_data,struct rte_flow_error * error)2301 flow_hw_action_handle_destroy(struct rte_eth_dev *dev, uint32_t queue,
2302 const struct rte_flow_op_attr *attr,
2303 struct rte_flow_action_handle *handle,
2304 void *user_data,
2305 struct rte_flow_error *error)
2306 {
2307 RTE_SET_USED(queue);
2308 RTE_SET_USED(attr);
2309 RTE_SET_USED(user_data);
2310 return flow_dv_action_destroy(dev, handle, error);
2311 }
2312
2313
2314 const struct mlx5_flow_driver_ops mlx5_flow_hw_drv_ops = {
2315 .info_get = flow_hw_info_get,
2316 .configure = flow_hw_configure,
2317 .pattern_template_create = flow_hw_pattern_template_create,
2318 .pattern_template_destroy = flow_hw_pattern_template_destroy,
2319 .actions_template_create = flow_hw_actions_template_create,
2320 .actions_template_destroy = flow_hw_actions_template_destroy,
2321 .template_table_create = flow_hw_table_create,
2322 .template_table_destroy = flow_hw_table_destroy,
2323 .async_flow_create = flow_hw_async_flow_create,
2324 .async_flow_destroy = flow_hw_async_flow_destroy,
2325 .pull = flow_hw_pull,
2326 .push = flow_hw_push,
2327 .async_action_create = flow_hw_action_handle_create,
2328 .async_action_destroy = flow_hw_action_handle_destroy,
2329 .async_action_update = flow_hw_action_handle_update,
2330 .action_validate = flow_dv_action_validate,
2331 .action_create = flow_dv_action_create,
2332 .action_destroy = flow_dv_action_destroy,
2333 .action_update = flow_dv_action_update,
2334 .action_query = flow_dv_action_query,
2335 };
2336
2337 #endif
2338