What can I help you with?
NVIDIA DPDK Documentation MLNX_DPDK_22.11_2310.5.1 LTS

Customized RSS Hash

An application can select various packet fields to serve as a hash calculation source and jump to the appropriate flow rule location. The RSS hash result will be used as the index in the table. For the linear hash function, the mapping is one-to-one and the hash result is the index. For other hash functions, the index is the hash result modulo table size. The RSS hash result can be retrieved via modify_field API: HASH_RESULT. In order to create RSS which is not natively supported by MLX5, the application may use the insert by index with default hash.

An example for this can be RSS on part of the IPv6 src/dest using mask on some of the lsb bits to align with Telco IPv6 subscriber's address allocation with fixed /64 msb and dynamic /64 lsb.

  • Select 64 most significant bits of IPv6 src and as a base for RSS hash calculation in a template

    Copy
    Copied!
                

    flow pattern_template 0 create pattern_template_id 1 ingress template ipv6 src mask ffff:ffff:ffff:ffff:0:0:0:0 / end

  • Distribute packets among all queues based on these fields

    Copy
    Copied!
                

    flow actions_template 0 create actions_template_id 1 template queue / end mask queue / end

  • Define a table with 4 entries and use insertion by index

    Copy
    Copied!
                

    flow template_table 0 create table_id 1 group 10 priority 0 ingress rules_number 4 insertion_type index hash_func default pattern_template 1 actions_template 1

  • Insert 4 flow rules to populate the whole table

    Copy
    Copied!
                

    flow queue 0 create 0 template_table 1 rule_index 0 actions_template 0 postpone no pattern end actions queue index 0 / end flow queue 0 create 0 template_table 1 rule_index 1 actions_template 0 postpone no pattern end actions queue index 1 / end flow queue 0 create 0 template_table 1 rule_index 2 actions_template 0 postpone no pattern end actions queue index 2 / end flow queue 0 create 0 template_table 1 rule_index 3 actions_template 0 postpone no pattern end actions queue index 3 / end

Copy
Copied!
            

struct rte_flow_pattern_template * create_pattern_template(uint16_t port_id, struct rte_flow_error *error) { const struct rte_flow_item_ipv6 ipv6_src_mask = { .hdr = { .src_addr = "\xff\xff\xff\xff\xff\xff\xff\xff” "\x00\x00\x00\x00\x00\x00\x00\x00", }, }; struct rte_flow_item pattern[] = { { .type = RTE_FLOW_ITEM_TYPE_IPV6, .mask = &ipv6_src_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_DEFAULT, }; 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"); }; } }

© Copyright 2024, NVIDIA. Last updated on Jan 9, 2025.