net: sched: extend flow_action_entry with destructor

Generalize flow_action_entry cleanup by extending the structure with
pointer to destructor function. Set the destructor in
tc_setup_flow_action(). Refactor tc_cleanup_flow_action() to call
entry->destructor() instead of using switch that dispatches by entry->id
and manually executes cleanup.

This refactoring is necessary for following patches in this series that
require destructor to use tc_action->ops callbacks that can't be easily
obtained in tc_cleanup_flow_action().

Signed-off-by: Vlad Buslov <vladbu@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Vlad Buslov 2019-09-13 18:28:39 +03:00 committed by David S. Miller
parent 28c9eb9042
commit 1158958a21
2 changed files with 50 additions and 33 deletions

View File

@ -154,8 +154,12 @@ enum flow_action_mangle_base {
FLOW_ACT_MANGLE_HDR_TYPE_UDP,
};
typedef void (*action_destr)(void *priv);
struct flow_action_entry {
enum flow_action_id id;
action_destr destructor;
void *destructor_priv;
union {
u32 chain_index; /* FLOW_ACTION_GOTO */
struct net_device *dev; /* FLOW_ACTION_REDIRECT */
@ -170,7 +174,7 @@ struct flow_action_entry {
u32 mask;
u32 val;
} mangle;
const struct ip_tunnel_info *tunnel; /* FLOW_ACTION_TUNNEL_ENCAP */
struct ip_tunnel_info *tunnel; /* FLOW_ACTION_TUNNEL_ENCAP */
u32 csum_flags; /* FLOW_ACTION_CSUM */
u32 mark; /* FLOW_ACTION_MARK */
u16 ptype; /* FLOW_ACTION_PTYPE */

View File

@ -3282,25 +3282,48 @@ void tc_cleanup_flow_action(struct flow_action *flow_action)
struct flow_action_entry *entry;
int i;
flow_action_for_each(i, entry, flow_action) {
switch (entry->id) {
case FLOW_ACTION_REDIRECT:
case FLOW_ACTION_MIRRED:
case FLOW_ACTION_REDIRECT_INGRESS:
case FLOW_ACTION_MIRRED_INGRESS:
if (entry->dev)
dev_put(entry->dev);
break;
case FLOW_ACTION_TUNNEL_ENCAP:
kfree(entry->tunnel);
break;
default:
break;
}
}
flow_action_for_each(i, entry, flow_action)
if (entry->destructor)
entry->destructor(entry->destructor_priv);
}
EXPORT_SYMBOL(tc_cleanup_flow_action);
static void tcf_mirred_put_dev(void *priv)
{
struct net_device *dev = priv;
dev_put(dev);
}
static void tcf_mirred_get_dev(struct flow_action_entry *entry,
const struct tc_action *act)
{
entry->dev = tcf_mirred_dev(act);
if (!entry->dev)
return;
dev_hold(entry->dev);
entry->destructor = tcf_mirred_put_dev;
entry->destructor_priv = entry->dev;
}
static void tcf_tunnel_encap_put_tunnel(void *priv)
{
struct ip_tunnel_info *tunnel = priv;
kfree(tunnel);
}
static int tcf_tunnel_encap_get_tunnel(struct flow_action_entry *entry,
const struct tc_action *act)
{
entry->tunnel = tcf_tunnel_info_copy(act);
if (!entry->tunnel)
return -ENOMEM;
entry->destructor = tcf_tunnel_encap_put_tunnel;
entry->destructor_priv = entry->tunnel;
return 0;
}
int tc_setup_flow_action(struct flow_action *flow_action,
const struct tcf_exts *exts, bool rtnl_held)
{
@ -3329,24 +3352,16 @@ int tc_setup_flow_action(struct flow_action *flow_action,
entry->chain_index = tcf_gact_goto_chain_index(act);
} else if (is_tcf_mirred_egress_redirect(act)) {
entry->id = FLOW_ACTION_REDIRECT;
entry->dev = tcf_mirred_dev(act);
if (entry->dev)
dev_hold(entry->dev);
tcf_mirred_get_dev(entry, act);
} else if (is_tcf_mirred_egress_mirror(act)) {
entry->id = FLOW_ACTION_MIRRED;
entry->dev = tcf_mirred_dev(act);
if (entry->dev)
dev_hold(entry->dev);
tcf_mirred_get_dev(entry, act);
} else if (is_tcf_mirred_ingress_redirect(act)) {
entry->id = FLOW_ACTION_REDIRECT_INGRESS;
entry->dev = tcf_mirred_dev(act);
if (entry->dev)
dev_hold(entry->dev);
tcf_mirred_get_dev(entry, act);
} else if (is_tcf_mirred_ingress_mirror(act)) {
entry->id = FLOW_ACTION_MIRRED_INGRESS;
entry->dev = tcf_mirred_dev(act);
if (entry->dev)
dev_hold(entry->dev);
tcf_mirred_get_dev(entry, act);
} else if (is_tcf_vlan(act)) {
switch (tcf_vlan_action(act)) {
case TCA_VLAN_ACT_PUSH:
@ -3370,11 +3385,9 @@ int tc_setup_flow_action(struct flow_action *flow_action,
}
} else if (is_tcf_tunnel_set(act)) {
entry->id = FLOW_ACTION_TUNNEL_ENCAP;
entry->tunnel = tcf_tunnel_info_copy(act);
if (!entry->tunnel) {
err = -ENOMEM;
err = tcf_tunnel_encap_get_tunnel(entry, act);
if (err)
goto err_out;
}
} else if (is_tcf_tunnel_release(act)) {
entry->id = FLOW_ACTION_TUNNEL_DECAP;
} else if (is_tcf_pedit(act)) {