Index-based Insertion Flow Rule
Flow rules can be inserted by calculating the hash value for the pattern or inserted by index via new a rte_flow_async_create_by_index() API. The index-based insertion enable the user to avoid additional match and simply execute predefined actions after jumping to the index in the table.
Specify special tag[255] as a pattern to jump to a particular index
flow pattern_template
0create pattern_template_id1ingress template tag index is255/ endSelect queue based on the index
flow actions_template
0create actions_template_id1template queue / end queue / endCreate a table with linear hash distribution and insertion by index type
flow template_table
0create table_id1group10priority0ingress rules_number65000insertion_type index hash_func linear pattern_template1actions_template1Distribute packets according to the index in tag[255]
flow queue
0create0template_table1rule_index0actions_template0postpone no pattern end actions queue index0/ end flow queue0create0template_table1rule_index1actions_template0postpone no pattern end actions queue index1/ end flow queue0create0template_table1rule_index2actions_template0postpone no pattern end actions queue index2/ end flow queue0create0template_table1rule_index3actions_template0postpone no pattern end actions queue index3/ end
            
            struct rte_flow_pattern_template *
create_pattern_template(uint16_t port_id, struct rte_flow_error *error)
{
                const struct rte_flow_item_tag tag_mask = {
                                .data = 0,
                                .index = MLX5_LINEAR_HASH_TAG_INDEX,
                };
                struct rte_flow_item pattern[] = {
                 {
                 .type = RTE_FLOW_ITEM_TYPE_TAG,
                 .mask = &tag_mask,
                 },
                 {
                 .type = RTE_FLOW_ITEM_TYPE_END,
                 },
                };
                const struct rte_flow_pattern_template_attr pt_attr = {
                 .relaxed_matching = 0,
                 .ingress = 1,
                };
                return rte_flow_pattern_template_create(port_id,
                                                                                                &pt_attr, pattern, &error);
}
 
struct rte_flow_actions_template *
create_actions_template(uint16_t port_id, struct rte_flow_error *error)
{
                struct rte_flow_action_queue queue_v = {
                                .index = 0
                };
                struct rte_flow_action_queue queue_m = {
                                .index = UINT16_MAX
                };
                struct rte_flow_action actions[] = {
                                [0] = { /* queue action. */
                                .type = RTE_FLOW_ACTION_TYPE_QUEUE,
                                .conf = &queue_v },
                                [1] = { /* end action mast be the last action. */
                                .type = RTE_FLOW_ACTION_TYPE_END,},
                };
                struct rte_flow_action masks[] = {
                                [0] = { /* queue action. */
                                .type = RTE_FLOW_ACTION_TYPE_QUEUE,
                                .conf = &queue_m },
                                [1] = { /* end action mast be the last action. */
                                .type = RTE_FLOW_ACTION_TYPE_END,},
                };
                const struct rte_flow_actions_template_attr at_attr = {
                                .ingress = 1,
                };
                return rte_flow_actions_template_create(port_id, &at_attr,
                                                                                actions, masks, error);
 
 }
 
struct rte_flow_template_table *
create_table(uint16_t port_id, struct rte_flow_error *error)
{
                struct rte_flow_pattern_template *pt;
                struct rte_flow_actions_template *at;
                const struct rte_flow_template_table_attr tbl_attr = {
                                .flow_attr = {
                                                .group = 1,
                                                .priority = 0,
                                                .ingress = 1,
                                },
                                .nb_flows = 4,
                                .insertion_type = RTE_FLOW_TABLE_INSERTION_TYPE_INDEX,
                                .hash_func = RTE_FLOW_TABLE_HASH_FUNC_LINEAR,                  
                };
                struc
                pt = create_pattern_template(port_id, error);
                if (pt == NULL) {
                                printf("Failed to create pattern template: %s (%d) \n",
                                                                error.message, rte_errno);
                                return NULL;
                }
                at = create_actions_template(port_id, error);
                if (at == NULL) {
                                printf("Failed to create actions template: %s (%d)\n",
                                                error.message, rte_errno);
                                return NULL;
                }
 
                return rte_flow_template_table_create(port_id, &tbl_attr,
                                                                                &pt, 1, &at, 1, error);
}
 
void
custom_hash_example(void)
{
                uint32_t idx;
                uint16_t port_id = PORT_ID;
                uint32_t queue_id = QUEUE_ID;
                struct rte_flow_error error = { 0 };
                struct rte_flow_op_attr attr = {
                                .postpone = 0,
                };
                struct rte_flow_action_queue queue = {
                                .index = 0
                };
                struct rte_flow_action actions[] = {
                                [0] = { /* queue action. */
                                .type = RTE_FLOW_ACTION_TYPE_QUEUE,
                                .conf = &queue },
                                [1] = { /* end action mast be the last action. */
                                .type = RTE_FLOW_ACTION_TYPE_END,},
                };
                struct rte_flow_template_table * table;
                struct rte_flow *flow;
 
                table = create_table(port_id, &error);
                if (table == NULL) {
                                printf("Failed to create template table: %s (%d)\n",
                                                error.message, rte_errno);
                                rte_exit(EXIT_FAILURE, "Exiting");
                }
 
                for (idx = 0, idx < 4, idx++) {
                                queue.index = idx;
                                flow = rte_flow_async_create_by_index(port_id, queue_id,
                                                                                &attr, table, idx, actions, 0, NULL, &error);
                                if (flow == NULL) {
                                                printf("Failed to enqueue flow create operation: %s (%d) \n",
                                                                                error.message, rte_errno);
                                                rte_exit(EXIT_FAILURE, "Exiting");
                                };
                }
}