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

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
Loading
Loading
Loading
Loading
+17 −0
Original line number Diff line number Diff line
@@ -59,4 +59,21 @@ static inline struct ip_tunnel_info *tcf_tunnel_info(const struct tc_action *a)
	return NULL;
#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 */
+8 −1
Original line number Diff line number Diff line
@@ -3279,6 +3279,9 @@ void tc_cleanup_flow_action(struct flow_action *flow_action)
			if (entry->dev)
				dev_put(entry->dev);
			break;
		case FLOW_ACTION_TUNNEL_ENCAP:
			kfree(entry->tunnel);
			break;
		default:
			break;
		}
@@ -3355,7 +3358,11 @@ 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(act);
			entry->tunnel = tcf_tunnel_info_copy(act);
			if (!entry->tunnel) {
				err = -ENOMEM;
				goto err_out;
			}
		} else if (is_tcf_tunnel_release(act)) {
			entry->id = FLOW_ACTION_TUNNEL_DECAP;
		} else if (is_tcf_pedit(act)) {