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
flow pattern_template
0
create pattern_template_id1
ingress template ipv6 src mask ffff:ffff:ffff:ffff:0
:0
:0
:0
/ endDistribute packets among all queues based on these fields
flow actions_template
0
create actions_template_id1
template queue / end mask queue / endDefine a table with 4 entries and use insertion by index
flow template_table
0
create table_id1
group10
priority0
ingress rules_number4
insertion_type index hash_funcdefault
pattern_template1
actions_template1
Insert 4 flow rules to populate the whole table
flow queue
0
create0
template_table1
rule_index0
actions_template0
postpone no pattern end actions queue index0
/ end flow queue0
create0
template_table1
rule_index1
actions_template0
postpone no pattern end actions queue index1
/ end flow queue0
create0
template_table1
rule_index2
actions_template0
postpone no pattern end actions queue index2
/ end flow queue0
create0
template_table1
rule_index3
actions_template0
postpone 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_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"
);
};
}
}