[PATCH v6 03/27] net/intel/common: add common flow action parsing

Burakov, Anatoly anatoly.burakov at intel.com
Thu Jun 4 17:50:19 CEST 2026


On 6/3/2026 3:03 PM, Bruce Richardson wrote:
> On Fri, May 29, 2026 at 04:36:05PM +0100, Anatoly Burakov wrote:
>> Currently, each driver has their own code for action parsing, which results
>> in a lot of duplication and subtle mismatches in behavior between drivers.
>>
>> Add common infrastructure, based on the following assumptions:
>>
>> - All drivers support at most 32 actions at once, but usually far less
>> - Not every action is supported by all drivers
>> - We can check a few common things to filter out obviously wrong actions
>> - Driver performs semantic checks on all valid actions
>>
>> So, the intention is to reject everything we can reasonably reject at the
>> outset without knowing anything about the drivers, parametrize what is
>> trivial to parametrize, and leave the rest for the driver to implement.
>>
>> While we're at it, also add logging infrastructure for Intel common code,
>> using the new component name defines that are automatically passed to each
>> DPDK driver as it is being built.
>>
>> Signed-off-by: Anatoly Burakov <anatoly.burakov at intel.com>
>> ---
>>   drivers/net/intel/common/flow_check.h | 279 ++++++++++++++++++++++++++
>>   drivers/net/intel/common/log.h        |  40 ++++
>>   2 files changed, 319 insertions(+)
>>   create mode 100644 drivers/net/intel/common/flow_check.h
>>   create mode 100644 drivers/net/intel/common/log.h
>>
> 
> <snip>
> 
>> +/**
>> + * Validate and parse a list of rte_flow_action into a parsed action list.
>> + *
>> + * @param actions pointer to array of rte_flow_action, terminated by RTE_FLOW_ACTION_TYPE_END
>> + * @param param pointer to ci_flow_actions_check_param structure (can be NULL)
>> + * @param parsed_actions pointer to ci_flow_actions structure to store parsed actions
>> + * @param error pointer to rte_flow_error structure for error reporting
>> + *
>> + * @return 0 on success, negative errno on failure.
>> + */
>> +static inline int
>> +ci_flow_check_actions(const struct rte_flow_action *actions,
>> +	const struct ci_flow_actions_check_param *param,
>> +	struct ci_flow_actions *parsed_actions,
>> +	struct rte_flow_error *error)
>> +{
>> +	size_t i = 0;
>> +	int ret;
>> +
>> +	if (actions == NULL) {
>> +		return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION,
>> +				NULL, "Missing actions");
>> +	}
>> +
>> +	/* reset the list */
>> +	*parsed_actions = (struct ci_flow_actions){0};
>> +
>> +	while (actions[i].type != RTE_FLOW_ACTION_TYPE_END) {
>> +		const struct rte_flow_action *action = &actions[i++];
>> +
>> +		/* skip VOID actions */
>> +		if (action->type == RTE_FLOW_ACTION_TYPE_VOID)
>> +			continue;
>> +
>> +		/* generic validation for actions - this will check against param as well */
>> +		ret = __flow_action_check_generic(action, param, error);
>> +		if (ret < 0)
>> +			return ret;
>> +
>> +		/* check against global maximum number of actions */
>> +		if (parsed_actions->count >= RTE_DIM(parsed_actions->actions)) {
>> +			return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION,
>> +							action, "Too many actions");
>> +		}
>> +		/* user may have specified a maximum number of actions */
>> +		if (param != NULL && param->max_actions != 0 &&
>> +		    parsed_actions->count >= param->max_actions) {
>> +			return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION,
>> +							action, "Too many actions");
>> +		}
>> +		/* add action to the list */
>> +		CI_DRV_LOG(DEBUG, "Parsed action %u: type=%s", parsed_actions->count,
>> +			   ci_flow_action_type_to_str(action->type));
>> +		parsed_actions->actions[parsed_actions->count++] = action;
>> +	}
>> +
>> +	/* now, call into user validation if specified */
>> +	if (param != NULL && param->check != NULL) {
>> +		ret = param->check(parsed_actions, param, error);
>> +		if (ret < 0)
>> +			return ret;
>> +	}
> 
> Running an AI review on this code myself, it highlights the fact that we
> are missing a check for an empty parsed_actions array here, and not all
> check handlers verify the length as being >0 before dereferencing. For
> example, in patch 10, the callbacks don't explicitly check for empty lists
> I think it would be reasonable to have the return -EINVAL before this
> callback check, right?

Yep, that is correct. Empty list should fail *before* we go into use 
callbacks. It is safe in the sense that references are never invalid, 
and well-behaved callbacks should check count, but that only reasonably 
applies to callbacks expecting multiple actions, but not just one.

> 
>> +	/* if we didn't parse anything, valid action list is empty */
>> +	return parsed_actions->count == 0 ? -EINVAL : 0;
>> +}
>> +
>> +#ifdef __cplusplus
>> +}
>> +#endif
> <snip>


-- 
Thanks,
Anatoly


More information about the dev mailing list