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);
}