flow_offload: allow user to offload tc action to net device

Use flow_indr_dev_register/flow_indr_dev_setup_offload to
offload tc action.

We need to call tc_cleanup_flow_action to clean up tc action entry since
in tc_setup_action, some actions may hold dev refcnt, especially the mirror
action.

Signed-off-by: Baowen Zheng <baowen.zheng@corigine.com>
Signed-off-by: Louis Peens <louis.peens@corigine.com>
Signed-off-by: Simon Horman <simon.horman@corigine.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Baowen Zheng
2021-12-17 19:16:22 +01:00
committed by David S. Miller
parent c54e1d920f
commit 8cbfe939ab
17 changed files with 254 additions and 23 deletions

View File

@@ -27,6 +27,26 @@ struct flow_rule *flow_rule_alloc(unsigned int num_actions)
}
EXPORT_SYMBOL(flow_rule_alloc);
struct flow_offload_action *offload_action_alloc(unsigned int num_actions)
{
struct flow_offload_action *fl_action;
int i;
fl_action = kzalloc(struct_size(fl_action, action.entries, num_actions),
GFP_KERNEL);
if (!fl_action)
return NULL;
fl_action->action.num_entries = num_actions;
/* Pre-fill each action hw_stats with DONT_CARE.
* Caller can override this if it wants stats for a given action.
*/
for (i = 0; i < num_actions; i++)
fl_action->action.entries[i].hw_stats = FLOW_ACTION_HW_STATS_DONT_CARE;
return fl_action;
}
#define FLOW_DISSECTOR_MATCH(__rule, __type, __out) \
const struct flow_match *__m = &(__rule)->match; \
struct flow_dissector *__d = (__m)->dissector; \
@@ -549,19 +569,25 @@ int flow_indr_dev_setup_offload(struct net_device *dev, struct Qdisc *sch,
void (*cleanup)(struct flow_block_cb *block_cb))
{
struct flow_indr_dev *this;
u32 count = 0;
int err;
mutex_lock(&flow_indr_block_lock);
if (bo) {
if (bo->command == FLOW_BLOCK_BIND)
indir_dev_add(data, dev, sch, type, cleanup, bo);
else if (bo->command == FLOW_BLOCK_UNBIND)
indir_dev_remove(data);
}
if (bo->command == FLOW_BLOCK_BIND)
indir_dev_add(data, dev, sch, type, cleanup, bo);
else if (bo->command == FLOW_BLOCK_UNBIND)
indir_dev_remove(data);
list_for_each_entry(this, &flow_block_indr_dev_list, list)
this->cb(dev, sch, this->cb_priv, type, bo, data, cleanup);
list_for_each_entry(this, &flow_block_indr_dev_list, list) {
err = this->cb(dev, sch, this->cb_priv, type, bo, data, cleanup);
if (!err)
count++;
}
mutex_unlock(&flow_indr_block_lock);
return list_empty(&bo->cb_list) ? -EOPNOTSUPP : 0;
return (bo && list_empty(&bo->cb_list)) ? -EOPNOTSUPP : count;
}
EXPORT_SYMBOL(flow_indr_dev_setup_offload);