Commit 1444c175 authored by Vlad Buslov's avatar Vlad Buslov Committed by David S. Miller

net: sched: copy tunnel info when setting flow_action entry->tunnel

In order to remove dependency on rtnl lock, modify tc_setup_flow_action()
to copy tunnel info, instead of just saving pointer to tunnel_key action
tunnel info. This is necessary to prevent concurrent action overwrite from
releasing tunnel info while it is being used by rtnl-unlocked driver.

Implement helper tcf_tunnel_info_copy() that is used to copy tunnel info
with all its options to dynamically allocated memory block. Modify
tc_cleanup_flow_action() to free dynamically allocated tunnel info.
Signed-off-by: default avatarVlad Buslov <vladbu@mellanox.com>
Acked-by: default avatarJiri Pirko <jiri@mellanox.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 5a6ff4b1
...@@ -59,4 +59,21 @@ static inline struct ip_tunnel_info *tcf_tunnel_info(const struct tc_action *a) ...@@ -59,4 +59,21 @@ static inline struct ip_tunnel_info *tcf_tunnel_info(const struct tc_action *a)
return NULL; return NULL;
#endif #endif
} }
static inline struct ip_tunnel_info *
tcf_tunnel_info_copy(const struct tc_action *a)
{
#ifdef CONFIG_NET_CLS_ACT
struct ip_tunnel_info *tun = tcf_tunnel_info(a);
if (tun) {
size_t tun_size = sizeof(*tun) + tun->options_len;
struct ip_tunnel_info *tun_copy = kmemdup(tun, tun_size,
GFP_KERNEL);
return tun_copy;
}
#endif
return NULL;
}
#endif /* __NET_TC_TUNNEL_KEY_H */ #endif /* __NET_TC_TUNNEL_KEY_H */
...@@ -3279,6 +3279,9 @@ void tc_cleanup_flow_action(struct flow_action *flow_action) ...@@ -3279,6 +3279,9 @@ void tc_cleanup_flow_action(struct flow_action *flow_action)
if (entry->dev) if (entry->dev)
dev_put(entry->dev); dev_put(entry->dev);
break; break;
case FLOW_ACTION_TUNNEL_ENCAP:
kfree(entry->tunnel);
break;
default: default:
break; break;
} }
...@@ -3355,7 +3358,11 @@ int tc_setup_flow_action(struct flow_action *flow_action, ...@@ -3355,7 +3358,11 @@ int tc_setup_flow_action(struct flow_action *flow_action,
} }
} else if (is_tcf_tunnel_set(act)) { } else if (is_tcf_tunnel_set(act)) {
entry->id = FLOW_ACTION_TUNNEL_ENCAP; entry->id = FLOW_ACTION_TUNNEL_ENCAP;
entry->tunnel = tcf_tunnel_info(act); entry->tunnel = tcf_tunnel_info_copy(act);
if (!entry->tunnel) {
err = -ENOMEM;
goto err_out;
}
} else if (is_tcf_tunnel_release(act)) { } else if (is_tcf_tunnel_release(act)) {
entry->id = FLOW_ACTION_TUNNEL_DECAP; entry->id = FLOW_ACTION_TUNNEL_DECAP;
} else if (is_tcf_pedit(act)) { } else if (is_tcf_pedit(act)) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment