1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright (c) 2022 NVIDIA Corporation & Affiliates
7 #include <mlx5_malloc.h>
11 #if defined(HAVE_IBV_FLOW_DV_SUPPORT) || !defined(HAVE_INFINIBAND_VERBS_H)
13 /* The maximum actions support in the flow. */
14 #define MLX5_HW_MAX_ACTS 16
16 /* Default push burst threshold. */
19 /* Default queue to flush the flows. */
20 #define MLX5_DEFAULT_FLUSH_QUEUE 0
22 const struct mlx5_flow_driver_ops mlx5_flow_hw_drv_ops;
24 /* DR action flags with different table. */
25 static uint32_t mlx5_hw_act_flag[MLX5_HW_ACTION_FLAG_MAX]
26 [MLX5DR_TABLE_TYPE_MAX] = {
28 MLX5DR_ACTION_FLAG_ROOT_RX,
29 MLX5DR_ACTION_FLAG_ROOT_TX,
30 MLX5DR_ACTION_FLAG_ROOT_FDB,
33 MLX5DR_ACTION_FLAG_HWS_RX,
34 MLX5DR_ACTION_FLAG_HWS_TX,
35 MLX5DR_ACTION_FLAG_HWS_FDB,
40 * Register destination table DR jump action.
43 * Pointer to the rte_eth_dev structure.
44 * @param[in] table_attr
45 * Pointer to the flow attributes.
46 * @param[in] dest_group
47 * The destination group ID.
49 * Pointer to error structure.
52 * Table on success, NULL otherwise and rte_errno is set.
54 static struct mlx5_hw_jump_action *
55 flow_hw_jump_action_register(struct rte_eth_dev *dev,
56 const struct rte_flow_attr *attr,
58 struct rte_flow_error *error)
60 struct mlx5_priv *priv = dev->data->dev_private;
61 struct rte_flow_attr jattr = *attr;
62 struct mlx5_flow_group *grp;
63 struct mlx5_flow_cb_ctx ctx = {
68 struct mlx5_list_entry *ge;
70 jattr.group = dest_group;
71 ge = mlx5_hlist_register(priv->sh->flow_tbls, dest_group, &ctx);
74 grp = container_of(ge, struct mlx5_flow_group, entry);
79 * Release jump action.
82 * Pointer to the rte_eth_dev structure.
84 * Pointer to the jump action.
88 flow_hw_jump_release(struct rte_eth_dev *dev, struct mlx5_hw_jump_action *jump)
90 struct mlx5_priv *priv = dev->data->dev_private;
91 struct mlx5_flow_group *grp;
94 (jump, struct mlx5_flow_group, jump);
95 mlx5_hlist_unregister(priv->sh->flow_tbls, &grp->entry);
99 * Destroy DR actions created by action template.
101 * For DR actions created during table creation's action translate.
102 * Need to destroy the DR action when destroying the table.
105 * Pointer to the rte_eth_dev structure.
107 * Pointer to the template HW steering DR actions.
110 __flow_hw_action_template_destroy(struct rte_eth_dev *dev,
111 struct mlx5_hw_actions *acts)
113 struct mlx5_priv *priv = dev->data->dev_private;
116 struct mlx5_flow_group *grp;
119 (acts->jump, struct mlx5_flow_group, jump);
120 mlx5_hlist_unregister(priv->sh->flow_tbls, &grp->entry);
126 * Append dynamic action to the dynamic action list.
129 * Pointer to the port private data structure.
131 * Pointer to the template HW steering DR actions.
134 * @param[in] action_src
135 * Offset of source rte flow action.
136 * @param[in] action_dst
137 * Offset of destination DR action.
140 * 0 on success, negative value otherwise and rte_errno is set.
142 static __rte_always_inline struct mlx5_action_construct_data *
143 __flow_hw_act_data_alloc(struct mlx5_priv *priv,
144 enum rte_flow_action_type type,
148 struct mlx5_action_construct_data *act_data;
151 act_data = mlx5_ipool_zmalloc(priv->acts_ipool, &idx);
155 act_data->type = type;
156 act_data->action_src = action_src;
157 act_data->action_dst = action_dst;
162 * Append dynamic action to the dynamic action list.
165 * Pointer to the port private data structure.
167 * Pointer to the template HW steering DR actions.
170 * @param[in] action_src
171 * Offset of source rte flow action.
172 * @param[in] action_dst
173 * Offset of destination DR action.
176 * 0 on success, negative value otherwise and rte_errno is set.
178 static __rte_always_inline int
179 __flow_hw_act_data_general_append(struct mlx5_priv *priv,
180 struct mlx5_hw_actions *acts,
181 enum rte_flow_action_type type,
184 { struct mlx5_action_construct_data *act_data;
186 act_data = __flow_hw_act_data_alloc(priv, type, action_src, action_dst);
189 LIST_INSERT_HEAD(&acts->act_list, act_data, next);
194 * Translate rte_flow actions to DR action.
196 * As the action template has already indicated the actions. Translate
197 * the rte_flow actions to DR action if possbile. So in flow create
198 * stage we will save cycles from handing the actions' organizing.
199 * For the actions with limited information, need to add these to a
203 * Pointer to the rte_eth_dev structure.
204 * @param[in] table_attr
205 * Pointer to the table attributes.
206 * @param[in] item_templates
207 * Item template array to be binded to the table.
208 * @param[in/out] acts
209 * Pointer to the template HW steering DR actions.
213 * Pointer to error structure.
216 * Table on success, NULL otherwise and rte_errno is set.
219 flow_hw_actions_translate(struct rte_eth_dev *dev,
220 const struct rte_flow_template_table_attr *table_attr,
221 struct mlx5_hw_actions *acts,
222 struct rte_flow_actions_template *at,
223 struct rte_flow_error *error)
225 struct mlx5_priv *priv = dev->data->dev_private;
226 const struct rte_flow_attr *attr = &table_attr->flow_attr;
227 struct rte_flow_action *actions = at->actions;
228 struct rte_flow_action *action_start = actions;
229 struct rte_flow_action *masks = at->masks;
230 bool actions_end = false;
235 type = MLX5DR_TABLE_TYPE_FDB;
236 else if (attr->egress)
237 type = MLX5DR_TABLE_TYPE_NIC_TX;
239 type = MLX5DR_TABLE_TYPE_NIC_RX;
240 for (i = 0; !actions_end; actions++, masks++) {
241 switch (actions->type) {
242 case RTE_FLOW_ACTION_TYPE_INDIRECT:
244 case RTE_FLOW_ACTION_TYPE_VOID:
246 case RTE_FLOW_ACTION_TYPE_DROP:
247 acts->rule_acts[i++].action =
248 priv->hw_drop[!!attr->group][type];
250 case RTE_FLOW_ACTION_TYPE_JUMP:
252 uint32_t jump_group =
253 ((const struct rte_flow_action_jump *)
254 actions->conf)->group;
255 acts->jump = flow_hw_jump_action_register
256 (dev, attr, jump_group, error);
259 acts->rule_acts[i].action = (!!attr->group) ?
260 acts->jump->hws_action :
261 acts->jump->root_action;
262 } else if (__flow_hw_act_data_general_append
263 (priv, acts, actions->type,
264 actions - action_start, i)){
269 case RTE_FLOW_ACTION_TYPE_END:
280 __flow_hw_action_template_destroy(dev, acts);
281 return rte_flow_error_set(error, err,
282 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
283 "fail to create rte table");
287 * Construct flow action array.
289 * For action template contains dynamic actions, these actions need to
290 * be updated according to the rte_flow action during flow creation.
293 * Pointer to the rte_eth_dev structure.
295 * Pointer to job descriptor.
297 * Pointer to translated actions from template.
299 * Array of rte_flow action need to be checked.
300 * @param[in] rule_acts
301 * Array of DR rule actions to be used during flow creation..
302 * @param[in] acts_num
303 * Pointer to the real acts_num flow has.
306 * 0 on success, negative value otherwise and rte_errno is set.
308 static __rte_always_inline int
309 flow_hw_actions_construct(struct rte_eth_dev *dev,
310 struct mlx5_hw_q_job *job,
311 struct mlx5_hw_actions *hw_acts,
312 const struct rte_flow_action actions[],
313 struct mlx5dr_rule_action *rule_acts,
316 struct rte_flow_template_table *table = job->flow->table;
317 struct mlx5_action_construct_data *act_data;
318 const struct rte_flow_action *action;
319 struct rte_flow_attr attr = {
323 memcpy(rule_acts, hw_acts->rule_acts,
324 sizeof(*rule_acts) * hw_acts->acts_num);
325 *acts_num = hw_acts->acts_num;
326 if (LIST_EMPTY(&hw_acts->act_list))
328 attr.group = table->grp->group_id;
329 if (table->type == MLX5DR_TABLE_TYPE_FDB) {
332 } else if (table->type == MLX5DR_TABLE_TYPE_NIC_TX) {
338 LIST_FOREACH(act_data, &hw_acts->act_list, next) {
340 struct mlx5_hw_jump_action *jump;
342 action = &actions[act_data->action_src];
343 MLX5_ASSERT(action->type == RTE_FLOW_ACTION_TYPE_INDIRECT ||
344 (int)action->type == act_data->type);
345 switch (action->type) {
346 case RTE_FLOW_ACTION_TYPE_INDIRECT:
348 case RTE_FLOW_ACTION_TYPE_VOID:
350 case RTE_FLOW_ACTION_TYPE_JUMP:
351 jump_group = ((const struct rte_flow_action_jump *)
352 action->conf)->group;
353 jump = flow_hw_jump_action_register
354 (dev, &attr, jump_group, NULL);
357 rule_acts[act_data->action_dst].action =
358 (!!attr.group) ? jump->hws_action : jump->root_action;
359 job->flow->jump = jump;
360 job->flow->fate_type = MLX5_FLOW_FATE_JUMP;
370 * Enqueue HW steering flow creation.
372 * The flow will be applied to the HW only if the postpone bit is not set or
373 * the extra push function is called.
374 * The flow creation status should be checked from dequeue result.
377 * Pointer to the rte_eth_dev structure.
379 * The queue to create the flow.
381 * Pointer to the flow operation attributes.
383 * Items with flow spec value.
384 * @param[in] pattern_template_index
385 * The item pattern flow follows from the table.
387 * Action with flow spec value.
388 * @param[in] action_template_index
389 * The action pattern flow follows from the table.
390 * @param[in] user_data
391 * Pointer to the user_data.
393 * Pointer to error structure.
396 * Flow pointer on success, NULL otherwise and rte_errno is set.
398 static struct rte_flow *
399 flow_hw_async_flow_create(struct rte_eth_dev *dev,
401 const struct rte_flow_op_attr *attr,
402 struct rte_flow_template_table *table,
403 const struct rte_flow_item items[],
404 uint8_t pattern_template_index,
405 const struct rte_flow_action actions[],
406 uint8_t action_template_index,
408 struct rte_flow_error *error)
410 struct mlx5_priv *priv = dev->data->dev_private;
411 struct mlx5dr_rule_attr rule_attr = {
413 .user_data = user_data,
414 .burst = attr->postpone,
416 struct mlx5dr_rule_action rule_acts[MLX5_HW_MAX_ACTS];
417 struct mlx5_hw_actions *hw_acts;
418 struct rte_flow_hw *flow;
419 struct mlx5_hw_q_job *job;
420 uint32_t acts_num, flow_idx;
423 if (unlikely(!priv->hw_q[queue].job_idx)) {
427 flow = mlx5_ipool_zmalloc(table->flow, &flow_idx);
431 * Set the table here in order to know the destination table
432 * when free the flow afterwards.
435 flow->idx = flow_idx;
436 job = priv->hw_q[queue].job[--priv->hw_q[queue].job_idx];
438 * Set the job type here in order to know if the flow memory
439 * should be freed or not when get the result from dequeue.
441 job->type = MLX5_HW_Q_JOB_TYPE_CREATE;
443 job->user_data = user_data;
444 rule_attr.user_data = job;
445 hw_acts = &table->ats[action_template_index].acts;
446 /* Construct the flow action array based on the input actions.*/
447 flow_hw_actions_construct(dev, job, hw_acts, actions,
448 rule_acts, &acts_num);
449 ret = mlx5dr_rule_create(table->matcher,
450 pattern_template_index, items,
452 &rule_attr, &flow->rule);
454 return (struct rte_flow *)flow;
455 /* Flow created fail, return the descriptor and flow memory. */
456 mlx5_ipool_free(table->flow, flow_idx);
457 priv->hw_q[queue].job_idx++;
459 rte_flow_error_set(error, rte_errno,
460 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
461 "fail to create rte flow");
466 * Enqueue HW steering flow destruction.
468 * The flow will be applied to the HW only if the postpone bit is not set or
469 * the extra push function is called.
470 * The flow destruction status should be checked from dequeue result.
473 * Pointer to the rte_eth_dev structure.
475 * The queue to destroy the flow.
477 * Pointer to the flow operation attributes.
479 * Pointer to the flow to be destroyed.
480 * @param[in] user_data
481 * Pointer to the user_data.
483 * Pointer to error structure.
486 * 0 on success, negative value otherwise and rte_errno is set.
489 flow_hw_async_flow_destroy(struct rte_eth_dev *dev,
491 const struct rte_flow_op_attr *attr,
492 struct rte_flow *flow,
494 struct rte_flow_error *error)
496 struct mlx5_priv *priv = dev->data->dev_private;
497 struct mlx5dr_rule_attr rule_attr = {
499 .user_data = user_data,
500 .burst = attr->postpone,
502 struct rte_flow_hw *fh = (struct rte_flow_hw *)flow;
503 struct mlx5_hw_q_job *job;
506 if (unlikely(!priv->hw_q[queue].job_idx)) {
510 job = priv->hw_q[queue].job[--priv->hw_q[queue].job_idx];
511 job->type = MLX5_HW_Q_JOB_TYPE_DESTROY;
512 job->user_data = user_data;
514 rule_attr.user_data = job;
515 ret = mlx5dr_rule_destroy(&fh->rule, &rule_attr);
518 priv->hw_q[queue].job_idx++;
520 return rte_flow_error_set(error, rte_errno,
521 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
522 "fail to create rte flow");
526 * Pull the enqueued flows.
528 * For flows enqueued from creation/destruction, the status should be
529 * checked from the dequeue result.
532 * Pointer to the rte_eth_dev structure.
534 * The queue to pull the result.
536 * Array to save the results.
538 * Available result with the array.
540 * Pointer to error structure.
543 * Result number on success, negative value otherwise and rte_errno is set.
546 flow_hw_pull(struct rte_eth_dev *dev,
548 struct rte_flow_op_result res[],
550 struct rte_flow_error *error)
552 struct mlx5_priv *priv = dev->data->dev_private;
553 struct mlx5_hw_q_job *job;
556 ret = mlx5dr_send_queue_poll(priv->dr_ctx, queue, res, n_res);
558 return rte_flow_error_set(error, rte_errno,
559 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
560 "fail to query flow queue");
561 for (i = 0; i < ret; i++) {
562 job = (struct mlx5_hw_q_job *)res[i].user_data;
563 /* Restore user data. */
564 res[i].user_data = job->user_data;
565 if (job->type == MLX5_HW_Q_JOB_TYPE_DESTROY) {
566 if (job->flow->fate_type == MLX5_FLOW_FATE_JUMP)
567 flow_hw_jump_release(dev, job->flow->jump);
568 mlx5_ipool_free(job->flow->table->flow, job->flow->idx);
570 priv->hw_q[queue].job[priv->hw_q[queue].job_idx++] = job;
576 * Push the enqueued flows to HW.
578 * Force apply all the enqueued flows to the HW.
581 * Pointer to the rte_eth_dev structure.
583 * The queue to push the flow.
585 * Pointer to error structure.
588 * 0 on success, negative value otherwise and rte_errno is set.
591 flow_hw_push(struct rte_eth_dev *dev,
593 struct rte_flow_error *error)
595 struct mlx5_priv *priv = dev->data->dev_private;
598 ret = mlx5dr_send_queue_action(priv->dr_ctx, queue,
599 MLX5DR_SEND_QUEUE_ACTION_DRAIN);
601 rte_flow_error_set(error, rte_errno,
602 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
603 "fail to push flows");
610 * Drain the enqueued flows' completion.
613 * Pointer to the rte_eth_dev structure.
615 * The queue to pull the flow.
616 * @param[in] pending_rules
617 * The pending flow number.
619 * Pointer to error structure.
622 * 0 on success, negative value otherwise and rte_errno is set.
625 __flow_hw_pull_comp(struct rte_eth_dev *dev,
627 uint32_t pending_rules,
628 struct rte_flow_error *error)
630 struct rte_flow_op_result comp[BURST_THR];
631 int ret, i, empty_loop = 0;
633 flow_hw_push(dev, queue, error);
634 while (pending_rules) {
635 ret = flow_hw_pull(dev, queue, comp, BURST_THR, error);
639 rte_delay_us_sleep(20000);
640 if (++empty_loop > 5) {
641 DRV_LOG(WARNING, "No available dequeue, quit.");
646 for (i = 0; i < ret; i++) {
647 if (comp[i].status == RTE_FLOW_OP_ERROR)
648 DRV_LOG(WARNING, "Flow flush get error CQE.");
650 if ((uint32_t)ret > pending_rules) {
651 DRV_LOG(WARNING, "Flow flush get extra CQE.");
652 return rte_flow_error_set(error, ERANGE,
653 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
656 pending_rules -= ret;
663 * Flush created flows.
666 * Pointer to the rte_eth_dev structure.
668 * Pointer to error structure.
671 * 0 on success, negative value otherwise and rte_errno is set.
674 flow_hw_q_flow_flush(struct rte_eth_dev *dev,
675 struct rte_flow_error *error)
677 struct mlx5_priv *priv = dev->data->dev_private;
678 struct mlx5_hw_q *hw_q;
679 struct rte_flow_template_table *tbl;
680 struct rte_flow_hw *flow;
681 struct rte_flow_op_attr attr = {
684 uint32_t pending_rules = 0;
689 * Ensure to push and dequeue all the enqueued flow
690 * creation/destruction jobs in case user forgot to
691 * dequeue. Or the enqueued created flows will be
692 * leaked. The forgotten dequeues would also cause
693 * flow flush get extra CQEs as expected and pending_rules
696 for (queue = 0; queue < priv->nb_queue; queue++) {
697 hw_q = &priv->hw_q[queue];
698 if (__flow_hw_pull_comp(dev, queue, hw_q->size - hw_q->job_idx,
702 /* Flush flow per-table from MLX5_DEFAULT_FLUSH_QUEUE. */
703 hw_q = &priv->hw_q[MLX5_DEFAULT_FLUSH_QUEUE];
704 LIST_FOREACH(tbl, &priv->flow_hw_tbl, next) {
705 MLX5_IPOOL_FOREACH(tbl->flow, fidx, flow) {
706 if (flow_hw_async_flow_destroy(dev,
707 MLX5_DEFAULT_FLUSH_QUEUE,
709 (struct rte_flow *)flow,
714 /* Drain completion with queue size. */
715 if (pending_rules >= hw_q->size) {
716 if (__flow_hw_pull_comp(dev,
717 MLX5_DEFAULT_FLUSH_QUEUE,
718 pending_rules, error))
724 /* Drain left completion. */
726 __flow_hw_pull_comp(dev, MLX5_DEFAULT_FLUSH_QUEUE, pending_rules,
735 * The input item and action templates will be binded to the table.
736 * Flow memory will also be allocated. Matcher will be created based
737 * on the item template. Action will be translated to the dedicated
738 * DR action if possible.
741 * Pointer to the rte_eth_dev structure.
743 * Pointer to the table attributes.
744 * @param[in] item_templates
745 * Item template array to be binded to the table.
746 * @param[in] nb_item_templates
747 * Number of item template.
748 * @param[in] action_templates
749 * Action template array to be binded to the table.
750 * @param[in] nb_action_templates
751 * Number of action template.
753 * Pointer to error structure.
756 * Table on success, NULL otherwise and rte_errno is set.
758 static struct rte_flow_template_table *
759 flow_hw_table_create(struct rte_eth_dev *dev,
760 const struct rte_flow_template_table_attr *attr,
761 struct rte_flow_pattern_template *item_templates[],
762 uint8_t nb_item_templates,
763 struct rte_flow_actions_template *action_templates[],
764 uint8_t nb_action_templates,
765 struct rte_flow_error *error)
767 struct mlx5_priv *priv = dev->data->dev_private;
768 struct mlx5dr_matcher_attr matcher_attr = {0};
769 struct rte_flow_template_table *tbl = NULL;
770 struct mlx5_flow_group *grp;
771 struct mlx5dr_match_template *mt[MLX5_HW_TBL_MAX_ITEM_TEMPLATE];
772 struct rte_flow_attr flow_attr = attr->flow_attr;
773 struct mlx5_flow_cb_ctx ctx = {
778 struct mlx5_indexed_pool_config cfg = {
779 .size = sizeof(struct rte_flow_hw),
780 .trunk_size = 1 << 12,
781 .per_core_cache = 1 << 13,
783 .release_mem_en = !!priv->sh->config.reclaim_mode,
784 .malloc = mlx5_malloc,
786 .type = "mlx5_hw_table_flow",
788 struct mlx5_list_entry *ge;
789 uint32_t i, max_tpl = MLX5_HW_TBL_MAX_ITEM_TEMPLATE;
790 uint32_t nb_flows = rte_align32pow2(attr->nb_flows);
793 /* HWS layer accepts only 1 item template with root table. */
794 if (!attr->flow_attr.group)
796 cfg.max_idx = nb_flows;
797 /* For table has very limited flows, disable cache. */
798 if (nb_flows < cfg.trunk_size) {
799 cfg.per_core_cache = 0;
800 cfg.trunk_size = nb_flows;
802 /* Check if we requires too many templates. */
803 if (nb_item_templates > max_tpl ||
804 nb_action_templates > MLX5_HW_TBL_MAX_ACTION_TEMPLATE) {
808 /* Allocate the table memory. */
809 tbl = mlx5_malloc(MLX5_MEM_ZERO, sizeof(*tbl), 0, rte_socket_id());
812 /* Allocate flow indexed pool. */
813 tbl->flow = mlx5_ipool_create(&cfg);
816 /* Register the flow group. */
817 ge = mlx5_hlist_register(priv->sh->groups, attr->flow_attr.group, &ctx);
820 grp = container_of(ge, struct mlx5_flow_group, entry);
822 /* Prepare matcher information. */
823 matcher_attr.priority = attr->flow_attr.priority;
824 matcher_attr.mode = MLX5DR_MATCHER_RESOURCE_MODE_RULE;
825 matcher_attr.rule.num_log = rte_log2_u32(nb_flows);
826 /* Build the item template. */
827 for (i = 0; i < nb_item_templates; i++) {
830 ret = __atomic_add_fetch(&item_templates[i]->refcnt, 1,
836 mt[i] = item_templates[i]->mt;
837 tbl->its[i] = item_templates[i];
839 tbl->matcher = mlx5dr_matcher_create
840 (tbl->grp->tbl, mt, nb_item_templates, &matcher_attr);
843 tbl->nb_item_templates = nb_item_templates;
844 /* Build the action template. */
845 for (i = 0; i < nb_action_templates; i++) {
848 ret = __atomic_add_fetch(&action_templates[i]->refcnt, 1,
854 LIST_INIT(&tbl->ats[i].acts.act_list);
855 err = flow_hw_actions_translate(dev, attr,
857 action_templates[i], error);
862 tbl->ats[i].action_template = action_templates[i];
864 tbl->nb_action_templates = nb_action_templates;
865 tbl->type = attr->flow_attr.transfer ? MLX5DR_TABLE_TYPE_FDB :
866 (attr->flow_attr.egress ? MLX5DR_TABLE_TYPE_NIC_TX :
867 MLX5DR_TABLE_TYPE_NIC_RX);
868 LIST_INSERT_HEAD(&priv->flow_hw_tbl, tbl, next);
872 __flow_hw_action_template_destroy(dev, &tbl->ats[i].acts);
873 __atomic_sub_fetch(&action_templates[i]->refcnt,
874 1, __ATOMIC_RELAXED);
876 i = nb_item_templates;
879 __atomic_sub_fetch(&item_templates[i]->refcnt,
880 1, __ATOMIC_RELAXED);
881 mlx5dr_matcher_destroy(tbl->matcher);
886 mlx5_hlist_unregister(priv->sh->groups,
889 mlx5_ipool_destroy(tbl->flow);
892 rte_flow_error_set(error, err,
893 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
894 "fail to create rte table");
899 * Destroy flow table.
902 * Pointer to the rte_eth_dev structure.
904 * Pointer to the table to be destroyed.
906 * Pointer to error structure.
909 * 0 on success, a negative errno value otherwise and rte_errno is set.
912 flow_hw_table_destroy(struct rte_eth_dev *dev,
913 struct rte_flow_template_table *table,
914 struct rte_flow_error *error)
916 struct mlx5_priv *priv = dev->data->dev_private;
920 DRV_LOG(WARNING, "Table %p is still in using.", (void *)table);
921 return rte_flow_error_set(error, EBUSY,
922 RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
926 LIST_REMOVE(table, next);
927 for (i = 0; i < table->nb_item_templates; i++)
928 __atomic_sub_fetch(&table->its[i]->refcnt,
929 1, __ATOMIC_RELAXED);
930 for (i = 0; i < table->nb_action_templates; i++) {
931 __flow_hw_action_template_destroy(dev, &table->ats[i].acts);
932 __atomic_sub_fetch(&table->ats[i].action_template->refcnt,
933 1, __ATOMIC_RELAXED);
935 mlx5dr_matcher_destroy(table->matcher);
936 mlx5_hlist_unregister(priv->sh->groups, &table->grp->entry);
937 mlx5_ipool_destroy(table->flow);
943 * Create flow action template.
946 * Pointer to the rte_eth_dev structure.
948 * Pointer to the action template attributes.
950 * Associated actions (list terminated by the END action).
952 * List of actions that marks which of the action's member is constant.
954 * Pointer to error structure.
957 * Action template pointer on success, NULL otherwise and rte_errno is set.
959 static struct rte_flow_actions_template *
960 flow_hw_actions_template_create(struct rte_eth_dev *dev,
961 const struct rte_flow_actions_template_attr *attr,
962 const struct rte_flow_action actions[],
963 const struct rte_flow_action masks[],
964 struct rte_flow_error *error)
966 struct mlx5_priv *priv = dev->data->dev_private;
967 int len, act_len, mask_len, i;
968 struct rte_flow_actions_template *at;
970 act_len = rte_flow_conv(RTE_FLOW_CONV_OP_ACTIONS,
971 NULL, 0, actions, error);
974 len = RTE_ALIGN(act_len, 16);
975 mask_len = rte_flow_conv(RTE_FLOW_CONV_OP_ACTIONS,
976 NULL, 0, masks, error);
979 len += RTE_ALIGN(mask_len, 16);
980 at = mlx5_malloc(MLX5_MEM_ZERO, len + sizeof(*at), 64, rte_socket_id());
982 rte_flow_error_set(error, ENOMEM,
983 RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
985 "cannot allocate action template");
989 at->actions = (struct rte_flow_action *)(at + 1);
990 act_len = rte_flow_conv(RTE_FLOW_CONV_OP_ACTIONS, at->actions, len,
994 at->masks = (struct rte_flow_action *)
995 (((uint8_t *)at->actions) + act_len);
996 mask_len = rte_flow_conv(RTE_FLOW_CONV_OP_ACTIONS, at->masks,
997 len - act_len, masks, error);
1001 * mlx5 PMD hacks indirect action index directly to the action conf.
1002 * The rte_flow_conv() function copies the content from conf pointer.
1003 * Need to restore the indirect action index from action conf here.
1005 for (i = 0; actions->type != RTE_FLOW_ACTION_TYPE_END;
1006 actions++, masks++, i++) {
1007 if (actions->type == RTE_FLOW_ACTION_TYPE_INDIRECT) {
1008 at->actions[i].conf = actions->conf;
1009 at->masks[i].conf = masks->conf;
1012 __atomic_fetch_add(&at->refcnt, 1, __ATOMIC_RELAXED);
1013 LIST_INSERT_HEAD(&priv->flow_hw_at, at, next);
1021 * Destroy flow action template.
1024 * Pointer to the rte_eth_dev structure.
1025 * @param[in] template
1026 * Pointer to the action template to be destroyed.
1028 * Pointer to error structure.
1031 * 0 on success, a negative errno value otherwise and rte_errno is set.
1034 flow_hw_actions_template_destroy(struct rte_eth_dev *dev __rte_unused,
1035 struct rte_flow_actions_template *template,
1036 struct rte_flow_error *error __rte_unused)
1038 if (__atomic_load_n(&template->refcnt, __ATOMIC_RELAXED) > 1) {
1039 DRV_LOG(WARNING, "Action template %p is still in use.",
1041 return rte_flow_error_set(error, EBUSY,
1042 RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1044 "action template in using");
1046 LIST_REMOVE(template, next);
1047 mlx5_free(template);
1052 * Create flow item template.
1055 * Pointer to the rte_eth_dev structure.
1057 * Pointer to the item template attributes.
1059 * The template item pattern.
1061 * Pointer to error structure.
1064 * Item template pointer on success, NULL otherwise and rte_errno is set.
1066 static struct rte_flow_pattern_template *
1067 flow_hw_pattern_template_create(struct rte_eth_dev *dev,
1068 const struct rte_flow_pattern_template_attr *attr,
1069 const struct rte_flow_item items[],
1070 struct rte_flow_error *error)
1072 struct mlx5_priv *priv = dev->data->dev_private;
1073 struct rte_flow_pattern_template *it;
1075 it = mlx5_malloc(MLX5_MEM_ZERO, sizeof(*it), 0, rte_socket_id());
1077 rte_flow_error_set(error, ENOMEM,
1078 RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1080 "cannot allocate item template");
1084 it->mt = mlx5dr_match_template_create(items, attr->relaxed_matching);
1087 rte_flow_error_set(error, rte_errno,
1088 RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1090 "cannot create match template");
1093 __atomic_fetch_add(&it->refcnt, 1, __ATOMIC_RELAXED);
1094 LIST_INSERT_HEAD(&priv->flow_hw_itt, it, next);
1099 * Destroy flow item template.
1102 * Pointer to the rte_eth_dev structure.
1103 * @param[in] template
1104 * Pointer to the item template to be destroyed.
1106 * Pointer to error structure.
1109 * 0 on success, a negative errno value otherwise and rte_errno is set.
1112 flow_hw_pattern_template_destroy(struct rte_eth_dev *dev __rte_unused,
1113 struct rte_flow_pattern_template *template,
1114 struct rte_flow_error *error __rte_unused)
1116 if (__atomic_load_n(&template->refcnt, __ATOMIC_RELAXED) > 1) {
1117 DRV_LOG(WARNING, "Item template %p is still in use.",
1119 return rte_flow_error_set(error, EBUSY,
1120 RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1122 "item template in using");
1124 LIST_REMOVE(template, next);
1125 claim_zero(mlx5dr_match_template_destroy(template->mt));
1126 mlx5_free(template);
1131 * Get information about HWS pre-configurable resources.
1134 * Pointer to the rte_eth_dev structure.
1135 * @param[out] port_info
1136 * Pointer to port information.
1137 * @param[out] queue_info
1138 * Pointer to queue information.
1140 * Pointer to error structure.
1143 * 0 on success, a negative errno value otherwise and rte_errno is set.
1146 flow_hw_info_get(struct rte_eth_dev *dev __rte_unused,
1147 struct rte_flow_port_info *port_info __rte_unused,
1148 struct rte_flow_queue_info *queue_info __rte_unused,
1149 struct rte_flow_error *error __rte_unused)
1151 /* Nothing to be updated currently. */
1152 memset(port_info, 0, sizeof(*port_info));
1153 /* Queue size is unlimited from low-level. */
1154 queue_info->max_size = UINT32_MAX;
1159 * Create group callback.
1161 * @param[in] tool_ctx
1162 * Pointer to the hash list related context.
1164 * Pointer to the group creation context.
1167 * Group entry on success, NULL otherwise and rte_errno is set.
1169 struct mlx5_list_entry *
1170 flow_hw_grp_create_cb(void *tool_ctx, void *cb_ctx)
1172 struct mlx5_dev_ctx_shared *sh = tool_ctx;
1173 struct mlx5_flow_cb_ctx *ctx = cb_ctx;
1174 struct rte_eth_dev *dev = ctx->dev;
1175 struct rte_flow_attr *attr = (struct rte_flow_attr *)ctx->data;
1176 struct mlx5_priv *priv = dev->data->dev_private;
1177 struct mlx5dr_table_attr dr_tbl_attr = {0};
1178 struct rte_flow_error *error = ctx->error;
1179 struct mlx5_flow_group *grp_data;
1180 struct mlx5dr_table *tbl = NULL;
1181 struct mlx5dr_action *jump;
1184 grp_data = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_HW_GRP], &idx);
1186 rte_flow_error_set(error, ENOMEM,
1187 RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1189 "cannot allocate flow table data entry");
1192 dr_tbl_attr.level = attr->group;
1194 dr_tbl_attr.type = MLX5DR_TABLE_TYPE_FDB;
1195 else if (attr->egress)
1196 dr_tbl_attr.type = MLX5DR_TABLE_TYPE_NIC_TX;
1198 dr_tbl_attr.type = MLX5DR_TABLE_TYPE_NIC_RX;
1199 tbl = mlx5dr_table_create(priv->dr_ctx, &dr_tbl_attr);
1202 grp_data->tbl = tbl;
1204 /* Jump action be used by non-root table. */
1205 jump = mlx5dr_action_create_dest_table
1207 mlx5_hw_act_flag[!!attr->group][dr_tbl_attr.type]);
1210 grp_data->jump.hws_action = jump;
1211 /* Jump action be used by root table. */
1212 jump = mlx5dr_action_create_dest_table
1214 mlx5_hw_act_flag[MLX5_HW_ACTION_FLAG_ROOT]
1215 [dr_tbl_attr.type]);
1218 grp_data->jump.root_action = jump;
1220 grp_data->idx = idx;
1221 grp_data->group_id = attr->group;
1222 grp_data->type = dr_tbl_attr.type;
1223 return &grp_data->entry;
1225 if (grp_data->jump.root_action)
1226 mlx5dr_action_destroy(grp_data->jump.root_action);
1227 if (grp_data->jump.hws_action)
1228 mlx5dr_action_destroy(grp_data->jump.hws_action);
1230 mlx5dr_table_destroy(tbl);
1232 mlx5_ipool_free(sh->ipool[MLX5_IPOOL_HW_GRP], idx);
1233 rte_flow_error_set(error, ENOMEM,
1234 RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1236 "cannot allocate flow dr table");
1241 * Remove group callback.
1243 * @param[in] tool_ctx
1244 * Pointer to the hash list related context.
1246 * Pointer to the entry to be removed.
1249 flow_hw_grp_remove_cb(void *tool_ctx, struct mlx5_list_entry *entry)
1251 struct mlx5_dev_ctx_shared *sh = tool_ctx;
1252 struct mlx5_flow_group *grp_data =
1253 container_of(entry, struct mlx5_flow_group, entry);
1255 MLX5_ASSERT(entry && sh);
1256 /* To use the wrapper glue functions instead. */
1257 if (grp_data->jump.hws_action)
1258 mlx5dr_action_destroy(grp_data->jump.hws_action);
1259 if (grp_data->jump.root_action)
1260 mlx5dr_action_destroy(grp_data->jump.root_action);
1261 mlx5dr_table_destroy(grp_data->tbl);
1262 mlx5_ipool_free(sh->ipool[MLX5_IPOOL_HW_GRP], grp_data->idx);
1266 * Match group callback.
1268 * @param[in] tool_ctx
1269 * Pointer to the hash list related context.
1271 * Pointer to the group to be matched.
1273 * Pointer to the group matching context.
1276 * 0 on matched, 1 on miss matched.
1279 flow_hw_grp_match_cb(void *tool_ctx __rte_unused, struct mlx5_list_entry *entry,
1282 struct mlx5_flow_cb_ctx *ctx = cb_ctx;
1283 struct mlx5_flow_group *grp_data =
1284 container_of(entry, struct mlx5_flow_group, entry);
1285 struct rte_flow_attr *attr =
1286 (struct rte_flow_attr *)ctx->data;
1288 return (grp_data->group_id != attr->group) ||
1289 ((grp_data->type != MLX5DR_TABLE_TYPE_FDB) &&
1291 ((grp_data->type != MLX5DR_TABLE_TYPE_NIC_TX) &&
1293 ((grp_data->type != MLX5DR_TABLE_TYPE_NIC_RX) &&
1298 * Clone group entry callback.
1300 * @param[in] tool_ctx
1301 * Pointer to the hash list related context.
1303 * Pointer to the group to be matched.
1305 * Pointer to the group matching context.
1308 * 0 on matched, 1 on miss matched.
1310 struct mlx5_list_entry *
1311 flow_hw_grp_clone_cb(void *tool_ctx, struct mlx5_list_entry *oentry,
1314 struct mlx5_dev_ctx_shared *sh = tool_ctx;
1315 struct mlx5_flow_cb_ctx *ctx = cb_ctx;
1316 struct mlx5_flow_group *grp_data;
1317 struct rte_flow_error *error = ctx->error;
1320 grp_data = mlx5_ipool_malloc(sh->ipool[MLX5_IPOOL_HW_GRP], &idx);
1322 rte_flow_error_set(error, ENOMEM,
1323 RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1325 "cannot allocate flow table data entry");
1328 memcpy(grp_data, oentry, sizeof(*grp_data));
1329 grp_data->idx = idx;
1330 return &grp_data->entry;
1334 * Free cloned group entry callback.
1336 * @param[in] tool_ctx
1337 * Pointer to the hash list related context.
1339 * Pointer to the group to be freed.
1342 flow_hw_grp_clone_free_cb(void *tool_ctx, struct mlx5_list_entry *entry)
1344 struct mlx5_dev_ctx_shared *sh = tool_ctx;
1345 struct mlx5_flow_group *grp_data =
1346 container_of(entry, struct mlx5_flow_group, entry);
1348 mlx5_ipool_free(sh->ipool[MLX5_IPOOL_HW_GRP], grp_data->idx);
1352 * Configure port HWS resources.
1355 * Pointer to the rte_eth_dev structure.
1356 * @param[in] port_attr
1357 * Port configuration attributes.
1358 * @param[in] nb_queue
1360 * @param[in] queue_attr
1361 * Array that holds attributes for each flow queue.
1363 * Pointer to error structure.
1366 * 0 on success, a negative errno value otherwise and rte_errno is set.
1370 flow_hw_configure(struct rte_eth_dev *dev,
1371 const struct rte_flow_port_attr *port_attr,
1373 const struct rte_flow_queue_attr *queue_attr[],
1374 struct rte_flow_error *error)
1376 struct mlx5_priv *priv = dev->data->dev_private;
1377 struct mlx5dr_context *dr_ctx = NULL;
1378 struct mlx5dr_context_attr dr_ctx_attr = {0};
1379 struct mlx5_hw_q *hw_q;
1380 struct mlx5_hw_q_job *job = NULL;
1381 uint32_t mem_size, i, j;
1382 struct mlx5_indexed_pool_config cfg = {
1383 .size = sizeof(struct rte_flow_hw),
1386 .release_mem_en = !!priv->sh->config.reclaim_mode,
1387 .malloc = mlx5_malloc,
1389 .type = "mlx5_hw_action_construct_data",
1392 if (!port_attr || !nb_queue || !queue_attr) {
1396 /* In case re-configuring, release existing context at first. */
1399 for (i = 0; i < nb_queue; i++) {
1400 hw_q = &priv->hw_q[i];
1401 /* Make sure all queues are empty. */
1402 if (hw_q->size != hw_q->job_idx) {
1407 flow_hw_resource_release(dev);
1409 priv->acts_ipool = mlx5_ipool_create(&cfg);
1410 if (!priv->acts_ipool)
1412 /* Allocate the queue job descriptor LIFO. */
1413 mem_size = sizeof(priv->hw_q[0]) * nb_queue;
1414 for (i = 0; i < nb_queue; i++) {
1416 * Check if the queues' size are all the same as the
1417 * limitation from HWS layer.
1419 if (queue_attr[i]->size != queue_attr[0]->size) {
1423 mem_size += (sizeof(struct mlx5_hw_q_job *) +
1424 sizeof(struct mlx5_hw_q_job)) *
1425 queue_attr[0]->size;
1427 priv->hw_q = mlx5_malloc(MLX5_MEM_ZERO, mem_size,
1433 for (i = 0; i < nb_queue; i++) {
1434 priv->hw_q[i].job_idx = queue_attr[i]->size;
1435 priv->hw_q[i].size = queue_attr[i]->size;
1437 priv->hw_q[i].job = (struct mlx5_hw_q_job **)
1438 &priv->hw_q[nb_queue];
1440 priv->hw_q[i].job = (struct mlx5_hw_q_job **)
1441 &job[queue_attr[i - 1]->size];
1442 job = (struct mlx5_hw_q_job *)
1443 &priv->hw_q[i].job[queue_attr[i]->size];
1444 for (j = 0; j < queue_attr[i]->size; j++)
1445 priv->hw_q[i].job[j] = &job[j];
1447 dr_ctx_attr.pd = priv->sh->cdev->pd;
1448 dr_ctx_attr.queues = nb_queue;
1449 /* Queue size should all be the same. Take the first one. */
1450 dr_ctx_attr.queue_size = queue_attr[0]->size;
1451 dr_ctx = mlx5dr_context_open(priv->sh->cdev->ctx, &dr_ctx_attr);
1452 /* rte_errno has been updated by HWS layer. */
1455 priv->dr_ctx = dr_ctx;
1456 priv->nb_queue = nb_queue;
1457 /* Add global actions. */
1458 for (i = 0; i < MLX5_HW_ACTION_FLAG_MAX; i++) {
1459 for (j = 0; j < MLX5DR_TABLE_TYPE_MAX; j++) {
1460 priv->hw_drop[i][j] = mlx5dr_action_create_dest_drop
1461 (priv->dr_ctx, mlx5_hw_act_flag[i][j]);
1462 if (!priv->hw_drop[i][j])
1468 for (i = 0; i < MLX5_HW_ACTION_FLAG_MAX; i++) {
1469 for (j = 0; j < MLX5DR_TABLE_TYPE_MAX; j++) {
1470 if (!priv->hw_drop[i][j])
1472 mlx5dr_action_destroy(priv->hw_drop[i][j]);
1476 claim_zero(mlx5dr_context_close(dr_ctx));
1477 mlx5_free(priv->hw_q);
1479 if (priv->acts_ipool) {
1480 mlx5_ipool_destroy(priv->acts_ipool);
1481 priv->acts_ipool = NULL;
1483 return rte_flow_error_set(error, rte_errno,
1484 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
1485 "fail to configure port");
1489 * Release HWS resources.
1492 * Pointer to the rte_eth_dev structure.
1495 flow_hw_resource_release(struct rte_eth_dev *dev)
1497 struct mlx5_priv *priv = dev->data->dev_private;
1498 struct rte_flow_template_table *tbl;
1499 struct rte_flow_pattern_template *it;
1500 struct rte_flow_actions_template *at;
1505 while (!LIST_EMPTY(&priv->flow_hw_tbl)) {
1506 tbl = LIST_FIRST(&priv->flow_hw_tbl);
1507 flow_hw_table_destroy(dev, tbl, NULL);
1509 while (!LIST_EMPTY(&priv->flow_hw_itt)) {
1510 it = LIST_FIRST(&priv->flow_hw_itt);
1511 flow_hw_pattern_template_destroy(dev, it, NULL);
1513 while (!LIST_EMPTY(&priv->flow_hw_at)) {
1514 at = LIST_FIRST(&priv->flow_hw_at);
1515 flow_hw_actions_template_destroy(dev, at, NULL);
1517 for (i = 0; i < MLX5_HW_ACTION_FLAG_MAX; i++) {
1518 for (j = 0; j < MLX5DR_TABLE_TYPE_MAX; j++) {
1519 if (!priv->hw_drop[i][j])
1521 mlx5dr_action_destroy(priv->hw_drop[i][j]);
1524 if (priv->acts_ipool) {
1525 mlx5_ipool_destroy(priv->acts_ipool);
1526 priv->acts_ipool = NULL;
1528 mlx5_free(priv->hw_q);
1530 claim_zero(mlx5dr_context_close(priv->dr_ctx));
1531 priv->dr_ctx = NULL;
1535 const struct mlx5_flow_driver_ops mlx5_flow_hw_drv_ops = {
1536 .info_get = flow_hw_info_get,
1537 .configure = flow_hw_configure,
1538 .pattern_template_create = flow_hw_pattern_template_create,
1539 .pattern_template_destroy = flow_hw_pattern_template_destroy,
1540 .actions_template_create = flow_hw_actions_template_create,
1541 .actions_template_destroy = flow_hw_actions_template_destroy,
1542 .template_table_create = flow_hw_table_create,
1543 .template_table_destroy = flow_hw_table_destroy,
1544 .async_flow_create = flow_hw_async_flow_create,
1545 .async_flow_destroy = flow_hw_async_flow_destroy,
1546 .pull = flow_hw_pull,
1547 .push = flow_hw_push,