Updating Flow Rule
The new rte_flow_update() API allows users to update the action list in the already existing rule. Flow rules can be updated now without the need to destroy the rule first and create a new one instead.
The update of the rule can have a different actions list.
# Create a template table with two templates.
flow pattern_template 0 create pattern_template_id 1 ingress template eth / end
flow actions_template 0 create actions_template_id 1 template queue / end mask queue / end
flow actions_template 0 create actions_template_id 2 template count / queue / end mask count / queue / end
flow template_table 0 create table_id 1 group 1 priority 0 ingress rules_number 64 pattern_template 1 actions_template 1 actions_template 2
# Create a flow with the counter to test the path.
flow queue 0 create 0 template_table 1 pattern_template 0 actions_template 1 postpone no pattern eth / end actions count / queue index 1 / end
# Remove counter by updating the rule once the path is tested.
flow queue 0 update 0 rule 1 actions_template 0 postpone no pattern end actions queue index 3 / end
struct rte_flow_pattern_template *
create_pattern_template(uint16_t port_id, struct rte_flow_error *error)
{
struct rte_flow_item pattern[] = {
{
.type = RTE_FLOW_ITEM_TYPE_ETH,
},
{
.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_templates(uint16_t port_id, bool counter, struct rte_flow_error *error)
{
struct rte_flow_action_count count;
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,
},
};
struct rte_flow_action cnt_actions[] = {
[0] = { /* counter action. */
.type = RTE_FLOW_ACTION_TYPE_COUNTER,
.conf = &count
},
[1] = { /* queue action. */
.type = RTE_FLOW_ACTION_TYPE_QUEUE,
.conf = &queue_v,
},
[2] = { /* end action mast be the last action. */
.type = RTE_FLOW_ACTION_TYPE_END,
},
};
struct rte_flow_action cnt_masks[] = {
[0] = { /* counter action. */
.type = RTE_FLOW_ACTION_TYPE_COUNTER,
.conf = &count
},
[1] = { /* queue action. */
.type = RTE_FLOW_ACTION_TYPE_QUEUE,
.conf = &queue_m,
},
[2] = { /* 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,
counter ? cnt_action : action,
counter ? cnt_masks : 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[2];
const struct rte_flow_template_table_attr tbl_attr = {
.flow_attr = {
.group = 1,
.priority = 0,
.ingress = 1,
},
.nb_flows = 1000,
};
...
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[0] = create_actions_template(port_id, false, error);
if (at[0] == NULL) {
printf("Failed to create actions template: %s (%d)\n",
error.message, rte_errno);
return NULL;
}
at[1] = create_actions_template(port_id, true, error);
if (at[1] == 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, 2, error);
}
void
update_counter_rule(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_item pattern[] = {
{
.type = RTE_FLOW_ITEM_TYPE_ETH,
},
{
.type = RTE_FLOW_ITEM_TYPE_END,
},
};
struct rte_flow_action_count count;
struct rte_flow_action_queue queue = { .index = 0 };
struct rte_flow_action cnt_actions[] = {
[0] = { /* counter action. */
.type = RTE_FLOW_ACTION_TYPE_COUNTER,
.conf = &count,
},
[1] = { /* queue action. */
.type = RTE_FLOW_ACTION_TYPE_QUEUE,
.conf = &queue,
},
[2] = { /* end action mast be the last action. */
.type = RTE_FLOW_ACTION_TYPE_END,
},
};
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");
}
flow = rte_flow_async_create(port_id, queue_id,
&attr, table, pattern, 0, cnt_actions, 1, NULL, &error);
if (flow == NULL) {
printf("Failed to enqueue flow create operation: %s (%d) \n",
error.message, rte_errno);
rte_exit(EXIT_FAILURE, "Exiting");
};
...
rte_flow_async_update(port_id, queue_id, &attr,
flow, actions, 0, NULL, &error);
}