xref: /OK3568_Linux_fs/kernel/net/sched/act_tunnel_key.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Copyright (c) 2016, Amir Vadai <amir@vadai.me>
4*4882a593Smuzhiyun  * Copyright (c) 2016, Mellanox Technologies. All rights reserved.
5*4882a593Smuzhiyun  */
6*4882a593Smuzhiyun 
7*4882a593Smuzhiyun #include <linux/module.h>
8*4882a593Smuzhiyun #include <linux/init.h>
9*4882a593Smuzhiyun #include <linux/kernel.h>
10*4882a593Smuzhiyun #include <linux/skbuff.h>
11*4882a593Smuzhiyun #include <linux/rtnetlink.h>
12*4882a593Smuzhiyun #include <net/geneve.h>
13*4882a593Smuzhiyun #include <net/vxlan.h>
14*4882a593Smuzhiyun #include <net/erspan.h>
15*4882a593Smuzhiyun #include <net/netlink.h>
16*4882a593Smuzhiyun #include <net/pkt_sched.h>
17*4882a593Smuzhiyun #include <net/dst.h>
18*4882a593Smuzhiyun #include <net/pkt_cls.h>
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun #include <linux/tc_act/tc_tunnel_key.h>
21*4882a593Smuzhiyun #include <net/tc_act/tc_tunnel_key.h>
22*4882a593Smuzhiyun 
23*4882a593Smuzhiyun static unsigned int tunnel_key_net_id;
24*4882a593Smuzhiyun static struct tc_action_ops act_tunnel_key_ops;
25*4882a593Smuzhiyun 
tunnel_key_act(struct sk_buff * skb,const struct tc_action * a,struct tcf_result * res)26*4882a593Smuzhiyun static int tunnel_key_act(struct sk_buff *skb, const struct tc_action *a,
27*4882a593Smuzhiyun 			  struct tcf_result *res)
28*4882a593Smuzhiyun {
29*4882a593Smuzhiyun 	struct tcf_tunnel_key *t = to_tunnel_key(a);
30*4882a593Smuzhiyun 	struct tcf_tunnel_key_params *params;
31*4882a593Smuzhiyun 	int action;
32*4882a593Smuzhiyun 
33*4882a593Smuzhiyun 	params = rcu_dereference_bh(t->params);
34*4882a593Smuzhiyun 
35*4882a593Smuzhiyun 	tcf_lastuse_update(&t->tcf_tm);
36*4882a593Smuzhiyun 	tcf_action_update_bstats(&t->common, skb);
37*4882a593Smuzhiyun 	action = READ_ONCE(t->tcf_action);
38*4882a593Smuzhiyun 
39*4882a593Smuzhiyun 	switch (params->tcft_action) {
40*4882a593Smuzhiyun 	case TCA_TUNNEL_KEY_ACT_RELEASE:
41*4882a593Smuzhiyun 		skb_dst_drop(skb);
42*4882a593Smuzhiyun 		break;
43*4882a593Smuzhiyun 	case TCA_TUNNEL_KEY_ACT_SET:
44*4882a593Smuzhiyun 		skb_dst_drop(skb);
45*4882a593Smuzhiyun 		skb_dst_set(skb, dst_clone(&params->tcft_enc_metadata->dst));
46*4882a593Smuzhiyun 		break;
47*4882a593Smuzhiyun 	default:
48*4882a593Smuzhiyun 		WARN_ONCE(1, "Bad tunnel_key action %d.\n",
49*4882a593Smuzhiyun 			  params->tcft_action);
50*4882a593Smuzhiyun 		break;
51*4882a593Smuzhiyun 	}
52*4882a593Smuzhiyun 
53*4882a593Smuzhiyun 	return action;
54*4882a593Smuzhiyun }
55*4882a593Smuzhiyun 
56*4882a593Smuzhiyun static const struct nla_policy
57*4882a593Smuzhiyun enc_opts_policy[TCA_TUNNEL_KEY_ENC_OPTS_MAX + 1] = {
58*4882a593Smuzhiyun 	[TCA_TUNNEL_KEY_ENC_OPTS_UNSPEC]	= {
59*4882a593Smuzhiyun 		.strict_start_type = TCA_TUNNEL_KEY_ENC_OPTS_VXLAN },
60*4882a593Smuzhiyun 	[TCA_TUNNEL_KEY_ENC_OPTS_GENEVE]	= { .type = NLA_NESTED },
61*4882a593Smuzhiyun 	[TCA_TUNNEL_KEY_ENC_OPTS_VXLAN]		= { .type = NLA_NESTED },
62*4882a593Smuzhiyun 	[TCA_TUNNEL_KEY_ENC_OPTS_ERSPAN]	= { .type = NLA_NESTED },
63*4882a593Smuzhiyun };
64*4882a593Smuzhiyun 
65*4882a593Smuzhiyun static const struct nla_policy
66*4882a593Smuzhiyun geneve_opt_policy[TCA_TUNNEL_KEY_ENC_OPT_GENEVE_MAX + 1] = {
67*4882a593Smuzhiyun 	[TCA_TUNNEL_KEY_ENC_OPT_GENEVE_CLASS]	   = { .type = NLA_U16 },
68*4882a593Smuzhiyun 	[TCA_TUNNEL_KEY_ENC_OPT_GENEVE_TYPE]	   = { .type = NLA_U8 },
69*4882a593Smuzhiyun 	[TCA_TUNNEL_KEY_ENC_OPT_GENEVE_DATA]	   = { .type = NLA_BINARY,
70*4882a593Smuzhiyun 						       .len = 128 },
71*4882a593Smuzhiyun };
72*4882a593Smuzhiyun 
73*4882a593Smuzhiyun static const struct nla_policy
74*4882a593Smuzhiyun vxlan_opt_policy[TCA_TUNNEL_KEY_ENC_OPT_VXLAN_MAX + 1] = {
75*4882a593Smuzhiyun 	[TCA_TUNNEL_KEY_ENC_OPT_VXLAN_GBP]	   = { .type = NLA_U32 },
76*4882a593Smuzhiyun };
77*4882a593Smuzhiyun 
78*4882a593Smuzhiyun static const struct nla_policy
79*4882a593Smuzhiyun erspan_opt_policy[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_MAX + 1] = {
80*4882a593Smuzhiyun 	[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_VER]	   = { .type = NLA_U8 },
81*4882a593Smuzhiyun 	[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_INDEX]	   = { .type = NLA_U32 },
82*4882a593Smuzhiyun 	[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_DIR]	   = { .type = NLA_U8 },
83*4882a593Smuzhiyun 	[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_HWID]	   = { .type = NLA_U8 },
84*4882a593Smuzhiyun };
85*4882a593Smuzhiyun 
86*4882a593Smuzhiyun static int
tunnel_key_copy_geneve_opt(const struct nlattr * nla,void * dst,int dst_len,struct netlink_ext_ack * extack)87*4882a593Smuzhiyun tunnel_key_copy_geneve_opt(const struct nlattr *nla, void *dst, int dst_len,
88*4882a593Smuzhiyun 			   struct netlink_ext_ack *extack)
89*4882a593Smuzhiyun {
90*4882a593Smuzhiyun 	struct nlattr *tb[TCA_TUNNEL_KEY_ENC_OPT_GENEVE_MAX + 1];
91*4882a593Smuzhiyun 	int err, data_len, opt_len;
92*4882a593Smuzhiyun 	u8 *data;
93*4882a593Smuzhiyun 
94*4882a593Smuzhiyun 	err = nla_parse_nested_deprecated(tb,
95*4882a593Smuzhiyun 					  TCA_TUNNEL_KEY_ENC_OPT_GENEVE_MAX,
96*4882a593Smuzhiyun 					  nla, geneve_opt_policy, extack);
97*4882a593Smuzhiyun 	if (err < 0)
98*4882a593Smuzhiyun 		return err;
99*4882a593Smuzhiyun 
100*4882a593Smuzhiyun 	if (!tb[TCA_TUNNEL_KEY_ENC_OPT_GENEVE_CLASS] ||
101*4882a593Smuzhiyun 	    !tb[TCA_TUNNEL_KEY_ENC_OPT_GENEVE_TYPE] ||
102*4882a593Smuzhiyun 	    !tb[TCA_TUNNEL_KEY_ENC_OPT_GENEVE_DATA]) {
103*4882a593Smuzhiyun 		NL_SET_ERR_MSG(extack, "Missing tunnel key geneve option class, type or data");
104*4882a593Smuzhiyun 		return -EINVAL;
105*4882a593Smuzhiyun 	}
106*4882a593Smuzhiyun 
107*4882a593Smuzhiyun 	data = nla_data(tb[TCA_TUNNEL_KEY_ENC_OPT_GENEVE_DATA]);
108*4882a593Smuzhiyun 	data_len = nla_len(tb[TCA_TUNNEL_KEY_ENC_OPT_GENEVE_DATA]);
109*4882a593Smuzhiyun 	if (data_len < 4) {
110*4882a593Smuzhiyun 		NL_SET_ERR_MSG(extack, "Tunnel key geneve option data is less than 4 bytes long");
111*4882a593Smuzhiyun 		return -ERANGE;
112*4882a593Smuzhiyun 	}
113*4882a593Smuzhiyun 	if (data_len % 4) {
114*4882a593Smuzhiyun 		NL_SET_ERR_MSG(extack, "Tunnel key geneve option data is not a multiple of 4 bytes long");
115*4882a593Smuzhiyun 		return -ERANGE;
116*4882a593Smuzhiyun 	}
117*4882a593Smuzhiyun 
118*4882a593Smuzhiyun 	opt_len = sizeof(struct geneve_opt) + data_len;
119*4882a593Smuzhiyun 	if (dst) {
120*4882a593Smuzhiyun 		struct geneve_opt *opt = dst;
121*4882a593Smuzhiyun 
122*4882a593Smuzhiyun 		WARN_ON(dst_len < opt_len);
123*4882a593Smuzhiyun 
124*4882a593Smuzhiyun 		opt->opt_class =
125*4882a593Smuzhiyun 			nla_get_be16(tb[TCA_TUNNEL_KEY_ENC_OPT_GENEVE_CLASS]);
126*4882a593Smuzhiyun 		opt->type = nla_get_u8(tb[TCA_TUNNEL_KEY_ENC_OPT_GENEVE_TYPE]);
127*4882a593Smuzhiyun 		opt->length = data_len / 4; /* length is in units of 4 bytes */
128*4882a593Smuzhiyun 		opt->r1 = 0;
129*4882a593Smuzhiyun 		opt->r2 = 0;
130*4882a593Smuzhiyun 		opt->r3 = 0;
131*4882a593Smuzhiyun 
132*4882a593Smuzhiyun 		memcpy(opt + 1, data, data_len);
133*4882a593Smuzhiyun 	}
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun 	return opt_len;
136*4882a593Smuzhiyun }
137*4882a593Smuzhiyun 
138*4882a593Smuzhiyun static int
tunnel_key_copy_vxlan_opt(const struct nlattr * nla,void * dst,int dst_len,struct netlink_ext_ack * extack)139*4882a593Smuzhiyun tunnel_key_copy_vxlan_opt(const struct nlattr *nla, void *dst, int dst_len,
140*4882a593Smuzhiyun 			  struct netlink_ext_ack *extack)
141*4882a593Smuzhiyun {
142*4882a593Smuzhiyun 	struct nlattr *tb[TCA_TUNNEL_KEY_ENC_OPT_VXLAN_MAX + 1];
143*4882a593Smuzhiyun 	int err;
144*4882a593Smuzhiyun 
145*4882a593Smuzhiyun 	err = nla_parse_nested(tb, TCA_TUNNEL_KEY_ENC_OPT_VXLAN_MAX, nla,
146*4882a593Smuzhiyun 			       vxlan_opt_policy, extack);
147*4882a593Smuzhiyun 	if (err < 0)
148*4882a593Smuzhiyun 		return err;
149*4882a593Smuzhiyun 
150*4882a593Smuzhiyun 	if (!tb[TCA_TUNNEL_KEY_ENC_OPT_VXLAN_GBP]) {
151*4882a593Smuzhiyun 		NL_SET_ERR_MSG(extack, "Missing tunnel key vxlan option gbp");
152*4882a593Smuzhiyun 		return -EINVAL;
153*4882a593Smuzhiyun 	}
154*4882a593Smuzhiyun 
155*4882a593Smuzhiyun 	if (dst) {
156*4882a593Smuzhiyun 		struct vxlan_metadata *md = dst;
157*4882a593Smuzhiyun 
158*4882a593Smuzhiyun 		md->gbp = nla_get_u32(tb[TCA_TUNNEL_KEY_ENC_OPT_VXLAN_GBP]);
159*4882a593Smuzhiyun 		md->gbp &= VXLAN_GBP_MASK;
160*4882a593Smuzhiyun 	}
161*4882a593Smuzhiyun 
162*4882a593Smuzhiyun 	return sizeof(struct vxlan_metadata);
163*4882a593Smuzhiyun }
164*4882a593Smuzhiyun 
165*4882a593Smuzhiyun static int
tunnel_key_copy_erspan_opt(const struct nlattr * nla,void * dst,int dst_len,struct netlink_ext_ack * extack)166*4882a593Smuzhiyun tunnel_key_copy_erspan_opt(const struct nlattr *nla, void *dst, int dst_len,
167*4882a593Smuzhiyun 			   struct netlink_ext_ack *extack)
168*4882a593Smuzhiyun {
169*4882a593Smuzhiyun 	struct nlattr *tb[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_MAX + 1];
170*4882a593Smuzhiyun 	int err;
171*4882a593Smuzhiyun 	u8 ver;
172*4882a593Smuzhiyun 
173*4882a593Smuzhiyun 	err = nla_parse_nested(tb, TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_MAX, nla,
174*4882a593Smuzhiyun 			       erspan_opt_policy, extack);
175*4882a593Smuzhiyun 	if (err < 0)
176*4882a593Smuzhiyun 		return err;
177*4882a593Smuzhiyun 
178*4882a593Smuzhiyun 	if (!tb[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_VER]) {
179*4882a593Smuzhiyun 		NL_SET_ERR_MSG(extack, "Missing tunnel key erspan option ver");
180*4882a593Smuzhiyun 		return -EINVAL;
181*4882a593Smuzhiyun 	}
182*4882a593Smuzhiyun 
183*4882a593Smuzhiyun 	ver = nla_get_u8(tb[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_VER]);
184*4882a593Smuzhiyun 	if (ver == 1) {
185*4882a593Smuzhiyun 		if (!tb[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_INDEX]) {
186*4882a593Smuzhiyun 			NL_SET_ERR_MSG(extack, "Missing tunnel key erspan option index");
187*4882a593Smuzhiyun 			return -EINVAL;
188*4882a593Smuzhiyun 		}
189*4882a593Smuzhiyun 	} else if (ver == 2) {
190*4882a593Smuzhiyun 		if (!tb[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_DIR] ||
191*4882a593Smuzhiyun 		    !tb[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_HWID]) {
192*4882a593Smuzhiyun 			NL_SET_ERR_MSG(extack, "Missing tunnel key erspan option dir or hwid");
193*4882a593Smuzhiyun 			return -EINVAL;
194*4882a593Smuzhiyun 		}
195*4882a593Smuzhiyun 	} else {
196*4882a593Smuzhiyun 		NL_SET_ERR_MSG(extack, "Tunnel key erspan option ver is incorrect");
197*4882a593Smuzhiyun 		return -EINVAL;
198*4882a593Smuzhiyun 	}
199*4882a593Smuzhiyun 
200*4882a593Smuzhiyun 	if (dst) {
201*4882a593Smuzhiyun 		struct erspan_metadata *md = dst;
202*4882a593Smuzhiyun 
203*4882a593Smuzhiyun 		md->version = ver;
204*4882a593Smuzhiyun 		if (ver == 1) {
205*4882a593Smuzhiyun 			nla = tb[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_INDEX];
206*4882a593Smuzhiyun 			md->u.index = nla_get_be32(nla);
207*4882a593Smuzhiyun 		} else {
208*4882a593Smuzhiyun 			nla = tb[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_DIR];
209*4882a593Smuzhiyun 			md->u.md2.dir = nla_get_u8(nla);
210*4882a593Smuzhiyun 			nla = tb[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_HWID];
211*4882a593Smuzhiyun 			set_hwid(&md->u.md2, nla_get_u8(nla));
212*4882a593Smuzhiyun 		}
213*4882a593Smuzhiyun 	}
214*4882a593Smuzhiyun 
215*4882a593Smuzhiyun 	return sizeof(struct erspan_metadata);
216*4882a593Smuzhiyun }
217*4882a593Smuzhiyun 
tunnel_key_copy_opts(const struct nlattr * nla,u8 * dst,int dst_len,struct netlink_ext_ack * extack)218*4882a593Smuzhiyun static int tunnel_key_copy_opts(const struct nlattr *nla, u8 *dst,
219*4882a593Smuzhiyun 				int dst_len, struct netlink_ext_ack *extack)
220*4882a593Smuzhiyun {
221*4882a593Smuzhiyun 	int err, rem, opt_len, len = nla_len(nla), opts_len = 0, type = 0;
222*4882a593Smuzhiyun 	const struct nlattr *attr, *head = nla_data(nla);
223*4882a593Smuzhiyun 
224*4882a593Smuzhiyun 	err = nla_validate_deprecated(head, len, TCA_TUNNEL_KEY_ENC_OPTS_MAX,
225*4882a593Smuzhiyun 				      enc_opts_policy, extack);
226*4882a593Smuzhiyun 	if (err)
227*4882a593Smuzhiyun 		return err;
228*4882a593Smuzhiyun 
229*4882a593Smuzhiyun 	nla_for_each_attr(attr, head, len, rem) {
230*4882a593Smuzhiyun 		switch (nla_type(attr)) {
231*4882a593Smuzhiyun 		case TCA_TUNNEL_KEY_ENC_OPTS_GENEVE:
232*4882a593Smuzhiyun 			if (type && type != TUNNEL_GENEVE_OPT) {
233*4882a593Smuzhiyun 				NL_SET_ERR_MSG(extack, "Duplicate type for geneve options");
234*4882a593Smuzhiyun 				return -EINVAL;
235*4882a593Smuzhiyun 			}
236*4882a593Smuzhiyun 			opt_len = tunnel_key_copy_geneve_opt(attr, dst,
237*4882a593Smuzhiyun 							     dst_len, extack);
238*4882a593Smuzhiyun 			if (opt_len < 0)
239*4882a593Smuzhiyun 				return opt_len;
240*4882a593Smuzhiyun 			opts_len += opt_len;
241*4882a593Smuzhiyun 			if (opts_len > IP_TUNNEL_OPTS_MAX) {
242*4882a593Smuzhiyun 				NL_SET_ERR_MSG(extack, "Tunnel options exceeds max size");
243*4882a593Smuzhiyun 				return -EINVAL;
244*4882a593Smuzhiyun 			}
245*4882a593Smuzhiyun 			if (dst) {
246*4882a593Smuzhiyun 				dst_len -= opt_len;
247*4882a593Smuzhiyun 				dst += opt_len;
248*4882a593Smuzhiyun 			}
249*4882a593Smuzhiyun 			type = TUNNEL_GENEVE_OPT;
250*4882a593Smuzhiyun 			break;
251*4882a593Smuzhiyun 		case TCA_TUNNEL_KEY_ENC_OPTS_VXLAN:
252*4882a593Smuzhiyun 			if (type) {
253*4882a593Smuzhiyun 				NL_SET_ERR_MSG(extack, "Duplicate type for vxlan options");
254*4882a593Smuzhiyun 				return -EINVAL;
255*4882a593Smuzhiyun 			}
256*4882a593Smuzhiyun 			opt_len = tunnel_key_copy_vxlan_opt(attr, dst,
257*4882a593Smuzhiyun 							    dst_len, extack);
258*4882a593Smuzhiyun 			if (opt_len < 0)
259*4882a593Smuzhiyun 				return opt_len;
260*4882a593Smuzhiyun 			opts_len += opt_len;
261*4882a593Smuzhiyun 			type = TUNNEL_VXLAN_OPT;
262*4882a593Smuzhiyun 			break;
263*4882a593Smuzhiyun 		case TCA_TUNNEL_KEY_ENC_OPTS_ERSPAN:
264*4882a593Smuzhiyun 			if (type) {
265*4882a593Smuzhiyun 				NL_SET_ERR_MSG(extack, "Duplicate type for erspan options");
266*4882a593Smuzhiyun 				return -EINVAL;
267*4882a593Smuzhiyun 			}
268*4882a593Smuzhiyun 			opt_len = tunnel_key_copy_erspan_opt(attr, dst,
269*4882a593Smuzhiyun 							     dst_len, extack);
270*4882a593Smuzhiyun 			if (opt_len < 0)
271*4882a593Smuzhiyun 				return opt_len;
272*4882a593Smuzhiyun 			opts_len += opt_len;
273*4882a593Smuzhiyun 			type = TUNNEL_ERSPAN_OPT;
274*4882a593Smuzhiyun 			break;
275*4882a593Smuzhiyun 		}
276*4882a593Smuzhiyun 	}
277*4882a593Smuzhiyun 
278*4882a593Smuzhiyun 	if (!opts_len) {
279*4882a593Smuzhiyun 		NL_SET_ERR_MSG(extack, "Empty list of tunnel options");
280*4882a593Smuzhiyun 		return -EINVAL;
281*4882a593Smuzhiyun 	}
282*4882a593Smuzhiyun 
283*4882a593Smuzhiyun 	if (rem > 0) {
284*4882a593Smuzhiyun 		NL_SET_ERR_MSG(extack, "Trailing data after parsing tunnel key options attributes");
285*4882a593Smuzhiyun 		return -EINVAL;
286*4882a593Smuzhiyun 	}
287*4882a593Smuzhiyun 
288*4882a593Smuzhiyun 	return opts_len;
289*4882a593Smuzhiyun }
290*4882a593Smuzhiyun 
tunnel_key_get_opts_len(struct nlattr * nla,struct netlink_ext_ack * extack)291*4882a593Smuzhiyun static int tunnel_key_get_opts_len(struct nlattr *nla,
292*4882a593Smuzhiyun 				   struct netlink_ext_ack *extack)
293*4882a593Smuzhiyun {
294*4882a593Smuzhiyun 	return tunnel_key_copy_opts(nla, NULL, 0, extack);
295*4882a593Smuzhiyun }
296*4882a593Smuzhiyun 
tunnel_key_opts_set(struct nlattr * nla,struct ip_tunnel_info * info,int opts_len,struct netlink_ext_ack * extack)297*4882a593Smuzhiyun static int tunnel_key_opts_set(struct nlattr *nla, struct ip_tunnel_info *info,
298*4882a593Smuzhiyun 			       int opts_len, struct netlink_ext_ack *extack)
299*4882a593Smuzhiyun {
300*4882a593Smuzhiyun 	info->options_len = opts_len;
301*4882a593Smuzhiyun 	switch (nla_type(nla_data(nla))) {
302*4882a593Smuzhiyun 	case TCA_TUNNEL_KEY_ENC_OPTS_GENEVE:
303*4882a593Smuzhiyun #if IS_ENABLED(CONFIG_INET)
304*4882a593Smuzhiyun 		info->key.tun_flags |= TUNNEL_GENEVE_OPT;
305*4882a593Smuzhiyun 		return tunnel_key_copy_opts(nla, ip_tunnel_info_opts(info),
306*4882a593Smuzhiyun 					    opts_len, extack);
307*4882a593Smuzhiyun #else
308*4882a593Smuzhiyun 		return -EAFNOSUPPORT;
309*4882a593Smuzhiyun #endif
310*4882a593Smuzhiyun 	case TCA_TUNNEL_KEY_ENC_OPTS_VXLAN:
311*4882a593Smuzhiyun #if IS_ENABLED(CONFIG_INET)
312*4882a593Smuzhiyun 		info->key.tun_flags |= TUNNEL_VXLAN_OPT;
313*4882a593Smuzhiyun 		return tunnel_key_copy_opts(nla, ip_tunnel_info_opts(info),
314*4882a593Smuzhiyun 					    opts_len, extack);
315*4882a593Smuzhiyun #else
316*4882a593Smuzhiyun 		return -EAFNOSUPPORT;
317*4882a593Smuzhiyun #endif
318*4882a593Smuzhiyun 	case TCA_TUNNEL_KEY_ENC_OPTS_ERSPAN:
319*4882a593Smuzhiyun #if IS_ENABLED(CONFIG_INET)
320*4882a593Smuzhiyun 		info->key.tun_flags |= TUNNEL_ERSPAN_OPT;
321*4882a593Smuzhiyun 		return tunnel_key_copy_opts(nla, ip_tunnel_info_opts(info),
322*4882a593Smuzhiyun 					    opts_len, extack);
323*4882a593Smuzhiyun #else
324*4882a593Smuzhiyun 		return -EAFNOSUPPORT;
325*4882a593Smuzhiyun #endif
326*4882a593Smuzhiyun 	default:
327*4882a593Smuzhiyun 		NL_SET_ERR_MSG(extack, "Cannot set tunnel options for unknown tunnel type");
328*4882a593Smuzhiyun 		return -EINVAL;
329*4882a593Smuzhiyun 	}
330*4882a593Smuzhiyun }
331*4882a593Smuzhiyun 
332*4882a593Smuzhiyun static const struct nla_policy tunnel_key_policy[TCA_TUNNEL_KEY_MAX + 1] = {
333*4882a593Smuzhiyun 	[TCA_TUNNEL_KEY_PARMS]	    = { .len = sizeof(struct tc_tunnel_key) },
334*4882a593Smuzhiyun 	[TCA_TUNNEL_KEY_ENC_IPV4_SRC] = { .type = NLA_U32 },
335*4882a593Smuzhiyun 	[TCA_TUNNEL_KEY_ENC_IPV4_DST] = { .type = NLA_U32 },
336*4882a593Smuzhiyun 	[TCA_TUNNEL_KEY_ENC_IPV6_SRC] = { .len = sizeof(struct in6_addr) },
337*4882a593Smuzhiyun 	[TCA_TUNNEL_KEY_ENC_IPV6_DST] = { .len = sizeof(struct in6_addr) },
338*4882a593Smuzhiyun 	[TCA_TUNNEL_KEY_ENC_KEY_ID]   = { .type = NLA_U32 },
339*4882a593Smuzhiyun 	[TCA_TUNNEL_KEY_ENC_DST_PORT] = {.type = NLA_U16},
340*4882a593Smuzhiyun 	[TCA_TUNNEL_KEY_NO_CSUM]      = { .type = NLA_U8 },
341*4882a593Smuzhiyun 	[TCA_TUNNEL_KEY_ENC_OPTS]     = { .type = NLA_NESTED },
342*4882a593Smuzhiyun 	[TCA_TUNNEL_KEY_ENC_TOS]      = { .type = NLA_U8 },
343*4882a593Smuzhiyun 	[TCA_TUNNEL_KEY_ENC_TTL]      = { .type = NLA_U8 },
344*4882a593Smuzhiyun };
345*4882a593Smuzhiyun 
tunnel_key_release_params(struct tcf_tunnel_key_params * p)346*4882a593Smuzhiyun static void tunnel_key_release_params(struct tcf_tunnel_key_params *p)
347*4882a593Smuzhiyun {
348*4882a593Smuzhiyun 	if (!p)
349*4882a593Smuzhiyun 		return;
350*4882a593Smuzhiyun 	if (p->tcft_action == TCA_TUNNEL_KEY_ACT_SET)
351*4882a593Smuzhiyun 		dst_release(&p->tcft_enc_metadata->dst);
352*4882a593Smuzhiyun 
353*4882a593Smuzhiyun 	kfree_rcu(p, rcu);
354*4882a593Smuzhiyun }
355*4882a593Smuzhiyun 
tunnel_key_init(struct net * net,struct nlattr * nla,struct nlattr * est,struct tc_action ** a,int ovr,int bind,bool rtnl_held,struct tcf_proto * tp,u32 act_flags,struct netlink_ext_ack * extack)356*4882a593Smuzhiyun static int tunnel_key_init(struct net *net, struct nlattr *nla,
357*4882a593Smuzhiyun 			   struct nlattr *est, struct tc_action **a,
358*4882a593Smuzhiyun 			   int ovr, int bind, bool rtnl_held,
359*4882a593Smuzhiyun 			   struct tcf_proto *tp, u32 act_flags,
360*4882a593Smuzhiyun 			   struct netlink_ext_ack *extack)
361*4882a593Smuzhiyun {
362*4882a593Smuzhiyun 	struct tc_action_net *tn = net_generic(net, tunnel_key_net_id);
363*4882a593Smuzhiyun 	struct nlattr *tb[TCA_TUNNEL_KEY_MAX + 1];
364*4882a593Smuzhiyun 	struct tcf_tunnel_key_params *params_new;
365*4882a593Smuzhiyun 	struct metadata_dst *metadata = NULL;
366*4882a593Smuzhiyun 	struct tcf_chain *goto_ch = NULL;
367*4882a593Smuzhiyun 	struct tc_tunnel_key *parm;
368*4882a593Smuzhiyun 	struct tcf_tunnel_key *t;
369*4882a593Smuzhiyun 	bool exists = false;
370*4882a593Smuzhiyun 	__be16 dst_port = 0;
371*4882a593Smuzhiyun 	__be64 key_id = 0;
372*4882a593Smuzhiyun 	int opts_len = 0;
373*4882a593Smuzhiyun 	__be16 flags = 0;
374*4882a593Smuzhiyun 	u8 tos, ttl;
375*4882a593Smuzhiyun 	int ret = 0;
376*4882a593Smuzhiyun 	u32 index;
377*4882a593Smuzhiyun 	int err;
378*4882a593Smuzhiyun 
379*4882a593Smuzhiyun 	if (!nla) {
380*4882a593Smuzhiyun 		NL_SET_ERR_MSG(extack, "Tunnel requires attributes to be passed");
381*4882a593Smuzhiyun 		return -EINVAL;
382*4882a593Smuzhiyun 	}
383*4882a593Smuzhiyun 
384*4882a593Smuzhiyun 	err = nla_parse_nested_deprecated(tb, TCA_TUNNEL_KEY_MAX, nla,
385*4882a593Smuzhiyun 					  tunnel_key_policy, extack);
386*4882a593Smuzhiyun 	if (err < 0) {
387*4882a593Smuzhiyun 		NL_SET_ERR_MSG(extack, "Failed to parse nested tunnel key attributes");
388*4882a593Smuzhiyun 		return err;
389*4882a593Smuzhiyun 	}
390*4882a593Smuzhiyun 
391*4882a593Smuzhiyun 	if (!tb[TCA_TUNNEL_KEY_PARMS]) {
392*4882a593Smuzhiyun 		NL_SET_ERR_MSG(extack, "Missing tunnel key parameters");
393*4882a593Smuzhiyun 		return -EINVAL;
394*4882a593Smuzhiyun 	}
395*4882a593Smuzhiyun 
396*4882a593Smuzhiyun 	parm = nla_data(tb[TCA_TUNNEL_KEY_PARMS]);
397*4882a593Smuzhiyun 	index = parm->index;
398*4882a593Smuzhiyun 	err = tcf_idr_check_alloc(tn, &index, a, bind);
399*4882a593Smuzhiyun 	if (err < 0)
400*4882a593Smuzhiyun 		return err;
401*4882a593Smuzhiyun 	exists = err;
402*4882a593Smuzhiyun 	if (exists && bind)
403*4882a593Smuzhiyun 		return 0;
404*4882a593Smuzhiyun 
405*4882a593Smuzhiyun 	switch (parm->t_action) {
406*4882a593Smuzhiyun 	case TCA_TUNNEL_KEY_ACT_RELEASE:
407*4882a593Smuzhiyun 		break;
408*4882a593Smuzhiyun 	case TCA_TUNNEL_KEY_ACT_SET:
409*4882a593Smuzhiyun 		if (tb[TCA_TUNNEL_KEY_ENC_KEY_ID]) {
410*4882a593Smuzhiyun 			__be32 key32;
411*4882a593Smuzhiyun 
412*4882a593Smuzhiyun 			key32 = nla_get_be32(tb[TCA_TUNNEL_KEY_ENC_KEY_ID]);
413*4882a593Smuzhiyun 			key_id = key32_to_tunnel_id(key32);
414*4882a593Smuzhiyun 			flags = TUNNEL_KEY;
415*4882a593Smuzhiyun 		}
416*4882a593Smuzhiyun 
417*4882a593Smuzhiyun 		flags |= TUNNEL_CSUM;
418*4882a593Smuzhiyun 		if (tb[TCA_TUNNEL_KEY_NO_CSUM] &&
419*4882a593Smuzhiyun 		    nla_get_u8(tb[TCA_TUNNEL_KEY_NO_CSUM]))
420*4882a593Smuzhiyun 			flags &= ~TUNNEL_CSUM;
421*4882a593Smuzhiyun 
422*4882a593Smuzhiyun 		if (tb[TCA_TUNNEL_KEY_ENC_DST_PORT])
423*4882a593Smuzhiyun 			dst_port = nla_get_be16(tb[TCA_TUNNEL_KEY_ENC_DST_PORT]);
424*4882a593Smuzhiyun 
425*4882a593Smuzhiyun 		if (tb[TCA_TUNNEL_KEY_ENC_OPTS]) {
426*4882a593Smuzhiyun 			opts_len = tunnel_key_get_opts_len(tb[TCA_TUNNEL_KEY_ENC_OPTS],
427*4882a593Smuzhiyun 							   extack);
428*4882a593Smuzhiyun 			if (opts_len < 0) {
429*4882a593Smuzhiyun 				ret = opts_len;
430*4882a593Smuzhiyun 				goto err_out;
431*4882a593Smuzhiyun 			}
432*4882a593Smuzhiyun 		}
433*4882a593Smuzhiyun 
434*4882a593Smuzhiyun 		tos = 0;
435*4882a593Smuzhiyun 		if (tb[TCA_TUNNEL_KEY_ENC_TOS])
436*4882a593Smuzhiyun 			tos = nla_get_u8(tb[TCA_TUNNEL_KEY_ENC_TOS]);
437*4882a593Smuzhiyun 		ttl = 0;
438*4882a593Smuzhiyun 		if (tb[TCA_TUNNEL_KEY_ENC_TTL])
439*4882a593Smuzhiyun 			ttl = nla_get_u8(tb[TCA_TUNNEL_KEY_ENC_TTL]);
440*4882a593Smuzhiyun 
441*4882a593Smuzhiyun 		if (tb[TCA_TUNNEL_KEY_ENC_IPV4_SRC] &&
442*4882a593Smuzhiyun 		    tb[TCA_TUNNEL_KEY_ENC_IPV4_DST]) {
443*4882a593Smuzhiyun 			__be32 saddr;
444*4882a593Smuzhiyun 			__be32 daddr;
445*4882a593Smuzhiyun 
446*4882a593Smuzhiyun 			saddr = nla_get_in_addr(tb[TCA_TUNNEL_KEY_ENC_IPV4_SRC]);
447*4882a593Smuzhiyun 			daddr = nla_get_in_addr(tb[TCA_TUNNEL_KEY_ENC_IPV4_DST]);
448*4882a593Smuzhiyun 
449*4882a593Smuzhiyun 			metadata = __ip_tun_set_dst(saddr, daddr, tos, ttl,
450*4882a593Smuzhiyun 						    dst_port, flags,
451*4882a593Smuzhiyun 						    key_id, opts_len);
452*4882a593Smuzhiyun 		} else if (tb[TCA_TUNNEL_KEY_ENC_IPV6_SRC] &&
453*4882a593Smuzhiyun 			   tb[TCA_TUNNEL_KEY_ENC_IPV6_DST]) {
454*4882a593Smuzhiyun 			struct in6_addr saddr;
455*4882a593Smuzhiyun 			struct in6_addr daddr;
456*4882a593Smuzhiyun 
457*4882a593Smuzhiyun 			saddr = nla_get_in6_addr(tb[TCA_TUNNEL_KEY_ENC_IPV6_SRC]);
458*4882a593Smuzhiyun 			daddr = nla_get_in6_addr(tb[TCA_TUNNEL_KEY_ENC_IPV6_DST]);
459*4882a593Smuzhiyun 
460*4882a593Smuzhiyun 			metadata = __ipv6_tun_set_dst(&saddr, &daddr, tos, ttl, dst_port,
461*4882a593Smuzhiyun 						      0, flags,
462*4882a593Smuzhiyun 						      key_id, opts_len);
463*4882a593Smuzhiyun 		} else {
464*4882a593Smuzhiyun 			NL_SET_ERR_MSG(extack, "Missing either ipv4 or ipv6 src and dst");
465*4882a593Smuzhiyun 			ret = -EINVAL;
466*4882a593Smuzhiyun 			goto err_out;
467*4882a593Smuzhiyun 		}
468*4882a593Smuzhiyun 
469*4882a593Smuzhiyun 		if (!metadata) {
470*4882a593Smuzhiyun 			NL_SET_ERR_MSG(extack, "Cannot allocate tunnel metadata dst");
471*4882a593Smuzhiyun 			ret = -ENOMEM;
472*4882a593Smuzhiyun 			goto err_out;
473*4882a593Smuzhiyun 		}
474*4882a593Smuzhiyun 
475*4882a593Smuzhiyun #ifdef CONFIG_DST_CACHE
476*4882a593Smuzhiyun 		ret = dst_cache_init(&metadata->u.tun_info.dst_cache, GFP_KERNEL);
477*4882a593Smuzhiyun 		if (ret)
478*4882a593Smuzhiyun 			goto release_tun_meta;
479*4882a593Smuzhiyun #endif
480*4882a593Smuzhiyun 
481*4882a593Smuzhiyun 		if (opts_len) {
482*4882a593Smuzhiyun 			ret = tunnel_key_opts_set(tb[TCA_TUNNEL_KEY_ENC_OPTS],
483*4882a593Smuzhiyun 						  &metadata->u.tun_info,
484*4882a593Smuzhiyun 						  opts_len, extack);
485*4882a593Smuzhiyun 			if (ret < 0)
486*4882a593Smuzhiyun 				goto release_tun_meta;
487*4882a593Smuzhiyun 		}
488*4882a593Smuzhiyun 
489*4882a593Smuzhiyun 		metadata->u.tun_info.mode |= IP_TUNNEL_INFO_TX;
490*4882a593Smuzhiyun 		break;
491*4882a593Smuzhiyun 	default:
492*4882a593Smuzhiyun 		NL_SET_ERR_MSG(extack, "Unknown tunnel key action");
493*4882a593Smuzhiyun 		ret = -EINVAL;
494*4882a593Smuzhiyun 		goto err_out;
495*4882a593Smuzhiyun 	}
496*4882a593Smuzhiyun 
497*4882a593Smuzhiyun 	if (!exists) {
498*4882a593Smuzhiyun 		ret = tcf_idr_create_from_flags(tn, index, est, a,
499*4882a593Smuzhiyun 						&act_tunnel_key_ops, bind,
500*4882a593Smuzhiyun 						act_flags);
501*4882a593Smuzhiyun 		if (ret) {
502*4882a593Smuzhiyun 			NL_SET_ERR_MSG(extack, "Cannot create TC IDR");
503*4882a593Smuzhiyun 			goto release_tun_meta;
504*4882a593Smuzhiyun 		}
505*4882a593Smuzhiyun 
506*4882a593Smuzhiyun 		ret = ACT_P_CREATED;
507*4882a593Smuzhiyun 	} else if (!ovr) {
508*4882a593Smuzhiyun 		NL_SET_ERR_MSG(extack, "TC IDR already exists");
509*4882a593Smuzhiyun 		ret = -EEXIST;
510*4882a593Smuzhiyun 		goto release_tun_meta;
511*4882a593Smuzhiyun 	}
512*4882a593Smuzhiyun 
513*4882a593Smuzhiyun 	err = tcf_action_check_ctrlact(parm->action, tp, &goto_ch, extack);
514*4882a593Smuzhiyun 	if (err < 0) {
515*4882a593Smuzhiyun 		ret = err;
516*4882a593Smuzhiyun 		exists = true;
517*4882a593Smuzhiyun 		goto release_tun_meta;
518*4882a593Smuzhiyun 	}
519*4882a593Smuzhiyun 	t = to_tunnel_key(*a);
520*4882a593Smuzhiyun 
521*4882a593Smuzhiyun 	params_new = kzalloc(sizeof(*params_new), GFP_KERNEL);
522*4882a593Smuzhiyun 	if (unlikely(!params_new)) {
523*4882a593Smuzhiyun 		NL_SET_ERR_MSG(extack, "Cannot allocate tunnel key parameters");
524*4882a593Smuzhiyun 		ret = -ENOMEM;
525*4882a593Smuzhiyun 		exists = true;
526*4882a593Smuzhiyun 		goto put_chain;
527*4882a593Smuzhiyun 	}
528*4882a593Smuzhiyun 	params_new->tcft_action = parm->t_action;
529*4882a593Smuzhiyun 	params_new->tcft_enc_metadata = metadata;
530*4882a593Smuzhiyun 
531*4882a593Smuzhiyun 	spin_lock_bh(&t->tcf_lock);
532*4882a593Smuzhiyun 	goto_ch = tcf_action_set_ctrlact(*a, parm->action, goto_ch);
533*4882a593Smuzhiyun 	params_new = rcu_replace_pointer(t->params, params_new,
534*4882a593Smuzhiyun 					 lockdep_is_held(&t->tcf_lock));
535*4882a593Smuzhiyun 	spin_unlock_bh(&t->tcf_lock);
536*4882a593Smuzhiyun 	tunnel_key_release_params(params_new);
537*4882a593Smuzhiyun 	if (goto_ch)
538*4882a593Smuzhiyun 		tcf_chain_put_by_act(goto_ch);
539*4882a593Smuzhiyun 
540*4882a593Smuzhiyun 	return ret;
541*4882a593Smuzhiyun 
542*4882a593Smuzhiyun put_chain:
543*4882a593Smuzhiyun 	if (goto_ch)
544*4882a593Smuzhiyun 		tcf_chain_put_by_act(goto_ch);
545*4882a593Smuzhiyun 
546*4882a593Smuzhiyun release_tun_meta:
547*4882a593Smuzhiyun 	if (metadata)
548*4882a593Smuzhiyun 		dst_release(&metadata->dst);
549*4882a593Smuzhiyun 
550*4882a593Smuzhiyun err_out:
551*4882a593Smuzhiyun 	if (exists)
552*4882a593Smuzhiyun 		tcf_idr_release(*a, bind);
553*4882a593Smuzhiyun 	else
554*4882a593Smuzhiyun 		tcf_idr_cleanup(tn, index);
555*4882a593Smuzhiyun 	return ret;
556*4882a593Smuzhiyun }
557*4882a593Smuzhiyun 
tunnel_key_release(struct tc_action * a)558*4882a593Smuzhiyun static void tunnel_key_release(struct tc_action *a)
559*4882a593Smuzhiyun {
560*4882a593Smuzhiyun 	struct tcf_tunnel_key *t = to_tunnel_key(a);
561*4882a593Smuzhiyun 	struct tcf_tunnel_key_params *params;
562*4882a593Smuzhiyun 
563*4882a593Smuzhiyun 	params = rcu_dereference_protected(t->params, 1);
564*4882a593Smuzhiyun 	tunnel_key_release_params(params);
565*4882a593Smuzhiyun }
566*4882a593Smuzhiyun 
tunnel_key_geneve_opts_dump(struct sk_buff * skb,const struct ip_tunnel_info * info)567*4882a593Smuzhiyun static int tunnel_key_geneve_opts_dump(struct sk_buff *skb,
568*4882a593Smuzhiyun 				       const struct ip_tunnel_info *info)
569*4882a593Smuzhiyun {
570*4882a593Smuzhiyun 	int len = info->options_len;
571*4882a593Smuzhiyun 	u8 *src = (u8 *)(info + 1);
572*4882a593Smuzhiyun 	struct nlattr *start;
573*4882a593Smuzhiyun 
574*4882a593Smuzhiyun 	start = nla_nest_start_noflag(skb, TCA_TUNNEL_KEY_ENC_OPTS_GENEVE);
575*4882a593Smuzhiyun 	if (!start)
576*4882a593Smuzhiyun 		return -EMSGSIZE;
577*4882a593Smuzhiyun 
578*4882a593Smuzhiyun 	while (len > 0) {
579*4882a593Smuzhiyun 		struct geneve_opt *opt = (struct geneve_opt *)src;
580*4882a593Smuzhiyun 
581*4882a593Smuzhiyun 		if (nla_put_be16(skb, TCA_TUNNEL_KEY_ENC_OPT_GENEVE_CLASS,
582*4882a593Smuzhiyun 				 opt->opt_class) ||
583*4882a593Smuzhiyun 		    nla_put_u8(skb, TCA_TUNNEL_KEY_ENC_OPT_GENEVE_TYPE,
584*4882a593Smuzhiyun 			       opt->type) ||
585*4882a593Smuzhiyun 		    nla_put(skb, TCA_TUNNEL_KEY_ENC_OPT_GENEVE_DATA,
586*4882a593Smuzhiyun 			    opt->length * 4, opt + 1)) {
587*4882a593Smuzhiyun 			nla_nest_cancel(skb, start);
588*4882a593Smuzhiyun 			return -EMSGSIZE;
589*4882a593Smuzhiyun 		}
590*4882a593Smuzhiyun 
591*4882a593Smuzhiyun 		len -= sizeof(struct geneve_opt) + opt->length * 4;
592*4882a593Smuzhiyun 		src += sizeof(struct geneve_opt) + opt->length * 4;
593*4882a593Smuzhiyun 	}
594*4882a593Smuzhiyun 
595*4882a593Smuzhiyun 	nla_nest_end(skb, start);
596*4882a593Smuzhiyun 	return 0;
597*4882a593Smuzhiyun }
598*4882a593Smuzhiyun 
tunnel_key_vxlan_opts_dump(struct sk_buff * skb,const struct ip_tunnel_info * info)599*4882a593Smuzhiyun static int tunnel_key_vxlan_opts_dump(struct sk_buff *skb,
600*4882a593Smuzhiyun 				      const struct ip_tunnel_info *info)
601*4882a593Smuzhiyun {
602*4882a593Smuzhiyun 	struct vxlan_metadata *md = (struct vxlan_metadata *)(info + 1);
603*4882a593Smuzhiyun 	struct nlattr *start;
604*4882a593Smuzhiyun 
605*4882a593Smuzhiyun 	start = nla_nest_start_noflag(skb, TCA_TUNNEL_KEY_ENC_OPTS_VXLAN);
606*4882a593Smuzhiyun 	if (!start)
607*4882a593Smuzhiyun 		return -EMSGSIZE;
608*4882a593Smuzhiyun 
609*4882a593Smuzhiyun 	if (nla_put_u32(skb, TCA_TUNNEL_KEY_ENC_OPT_VXLAN_GBP, md->gbp)) {
610*4882a593Smuzhiyun 		nla_nest_cancel(skb, start);
611*4882a593Smuzhiyun 		return -EMSGSIZE;
612*4882a593Smuzhiyun 	}
613*4882a593Smuzhiyun 
614*4882a593Smuzhiyun 	nla_nest_end(skb, start);
615*4882a593Smuzhiyun 	return 0;
616*4882a593Smuzhiyun }
617*4882a593Smuzhiyun 
tunnel_key_erspan_opts_dump(struct sk_buff * skb,const struct ip_tunnel_info * info)618*4882a593Smuzhiyun static int tunnel_key_erspan_opts_dump(struct sk_buff *skb,
619*4882a593Smuzhiyun 				       const struct ip_tunnel_info *info)
620*4882a593Smuzhiyun {
621*4882a593Smuzhiyun 	struct erspan_metadata *md = (struct erspan_metadata *)(info + 1);
622*4882a593Smuzhiyun 	struct nlattr *start;
623*4882a593Smuzhiyun 
624*4882a593Smuzhiyun 	start = nla_nest_start_noflag(skb, TCA_TUNNEL_KEY_ENC_OPTS_ERSPAN);
625*4882a593Smuzhiyun 	if (!start)
626*4882a593Smuzhiyun 		return -EMSGSIZE;
627*4882a593Smuzhiyun 
628*4882a593Smuzhiyun 	if (nla_put_u8(skb, TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_VER, md->version))
629*4882a593Smuzhiyun 		goto err;
630*4882a593Smuzhiyun 
631*4882a593Smuzhiyun 	if (md->version == 1 &&
632*4882a593Smuzhiyun 	    nla_put_be32(skb, TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_INDEX, md->u.index))
633*4882a593Smuzhiyun 		goto err;
634*4882a593Smuzhiyun 
635*4882a593Smuzhiyun 	if (md->version == 2 &&
636*4882a593Smuzhiyun 	    (nla_put_u8(skb, TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_DIR,
637*4882a593Smuzhiyun 			md->u.md2.dir) ||
638*4882a593Smuzhiyun 	     nla_put_u8(skb, TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_HWID,
639*4882a593Smuzhiyun 			get_hwid(&md->u.md2))))
640*4882a593Smuzhiyun 		goto err;
641*4882a593Smuzhiyun 
642*4882a593Smuzhiyun 	nla_nest_end(skb, start);
643*4882a593Smuzhiyun 	return 0;
644*4882a593Smuzhiyun err:
645*4882a593Smuzhiyun 	nla_nest_cancel(skb, start);
646*4882a593Smuzhiyun 	return -EMSGSIZE;
647*4882a593Smuzhiyun }
648*4882a593Smuzhiyun 
tunnel_key_opts_dump(struct sk_buff * skb,const struct ip_tunnel_info * info)649*4882a593Smuzhiyun static int tunnel_key_opts_dump(struct sk_buff *skb,
650*4882a593Smuzhiyun 				const struct ip_tunnel_info *info)
651*4882a593Smuzhiyun {
652*4882a593Smuzhiyun 	struct nlattr *start;
653*4882a593Smuzhiyun 	int err = -EINVAL;
654*4882a593Smuzhiyun 
655*4882a593Smuzhiyun 	if (!info->options_len)
656*4882a593Smuzhiyun 		return 0;
657*4882a593Smuzhiyun 
658*4882a593Smuzhiyun 	start = nla_nest_start_noflag(skb, TCA_TUNNEL_KEY_ENC_OPTS);
659*4882a593Smuzhiyun 	if (!start)
660*4882a593Smuzhiyun 		return -EMSGSIZE;
661*4882a593Smuzhiyun 
662*4882a593Smuzhiyun 	if (info->key.tun_flags & TUNNEL_GENEVE_OPT) {
663*4882a593Smuzhiyun 		err = tunnel_key_geneve_opts_dump(skb, info);
664*4882a593Smuzhiyun 		if (err)
665*4882a593Smuzhiyun 			goto err_out;
666*4882a593Smuzhiyun 	} else if (info->key.tun_flags & TUNNEL_VXLAN_OPT) {
667*4882a593Smuzhiyun 		err = tunnel_key_vxlan_opts_dump(skb, info);
668*4882a593Smuzhiyun 		if (err)
669*4882a593Smuzhiyun 			goto err_out;
670*4882a593Smuzhiyun 	} else if (info->key.tun_flags & TUNNEL_ERSPAN_OPT) {
671*4882a593Smuzhiyun 		err = tunnel_key_erspan_opts_dump(skb, info);
672*4882a593Smuzhiyun 		if (err)
673*4882a593Smuzhiyun 			goto err_out;
674*4882a593Smuzhiyun 	} else {
675*4882a593Smuzhiyun err_out:
676*4882a593Smuzhiyun 		nla_nest_cancel(skb, start);
677*4882a593Smuzhiyun 		return err;
678*4882a593Smuzhiyun 	}
679*4882a593Smuzhiyun 
680*4882a593Smuzhiyun 	nla_nest_end(skb, start);
681*4882a593Smuzhiyun 	return 0;
682*4882a593Smuzhiyun }
683*4882a593Smuzhiyun 
tunnel_key_dump_addresses(struct sk_buff * skb,const struct ip_tunnel_info * info)684*4882a593Smuzhiyun static int tunnel_key_dump_addresses(struct sk_buff *skb,
685*4882a593Smuzhiyun 				     const struct ip_tunnel_info *info)
686*4882a593Smuzhiyun {
687*4882a593Smuzhiyun 	unsigned short family = ip_tunnel_info_af(info);
688*4882a593Smuzhiyun 
689*4882a593Smuzhiyun 	if (family == AF_INET) {
690*4882a593Smuzhiyun 		__be32 saddr = info->key.u.ipv4.src;
691*4882a593Smuzhiyun 		__be32 daddr = info->key.u.ipv4.dst;
692*4882a593Smuzhiyun 
693*4882a593Smuzhiyun 		if (!nla_put_in_addr(skb, TCA_TUNNEL_KEY_ENC_IPV4_SRC, saddr) &&
694*4882a593Smuzhiyun 		    !nla_put_in_addr(skb, TCA_TUNNEL_KEY_ENC_IPV4_DST, daddr))
695*4882a593Smuzhiyun 			return 0;
696*4882a593Smuzhiyun 	}
697*4882a593Smuzhiyun 
698*4882a593Smuzhiyun 	if (family == AF_INET6) {
699*4882a593Smuzhiyun 		const struct in6_addr *saddr6 = &info->key.u.ipv6.src;
700*4882a593Smuzhiyun 		const struct in6_addr *daddr6 = &info->key.u.ipv6.dst;
701*4882a593Smuzhiyun 
702*4882a593Smuzhiyun 		if (!nla_put_in6_addr(skb,
703*4882a593Smuzhiyun 				      TCA_TUNNEL_KEY_ENC_IPV6_SRC, saddr6) &&
704*4882a593Smuzhiyun 		    !nla_put_in6_addr(skb,
705*4882a593Smuzhiyun 				      TCA_TUNNEL_KEY_ENC_IPV6_DST, daddr6))
706*4882a593Smuzhiyun 			return 0;
707*4882a593Smuzhiyun 	}
708*4882a593Smuzhiyun 
709*4882a593Smuzhiyun 	return -EINVAL;
710*4882a593Smuzhiyun }
711*4882a593Smuzhiyun 
tunnel_key_dump(struct sk_buff * skb,struct tc_action * a,int bind,int ref)712*4882a593Smuzhiyun static int tunnel_key_dump(struct sk_buff *skb, struct tc_action *a,
713*4882a593Smuzhiyun 			   int bind, int ref)
714*4882a593Smuzhiyun {
715*4882a593Smuzhiyun 	unsigned char *b = skb_tail_pointer(skb);
716*4882a593Smuzhiyun 	struct tcf_tunnel_key *t = to_tunnel_key(a);
717*4882a593Smuzhiyun 	struct tcf_tunnel_key_params *params;
718*4882a593Smuzhiyun 	struct tc_tunnel_key opt = {
719*4882a593Smuzhiyun 		.index    = t->tcf_index,
720*4882a593Smuzhiyun 		.refcnt   = refcount_read(&t->tcf_refcnt) - ref,
721*4882a593Smuzhiyun 		.bindcnt  = atomic_read(&t->tcf_bindcnt) - bind,
722*4882a593Smuzhiyun 	};
723*4882a593Smuzhiyun 	struct tcf_t tm;
724*4882a593Smuzhiyun 
725*4882a593Smuzhiyun 	spin_lock_bh(&t->tcf_lock);
726*4882a593Smuzhiyun 	params = rcu_dereference_protected(t->params,
727*4882a593Smuzhiyun 					   lockdep_is_held(&t->tcf_lock));
728*4882a593Smuzhiyun 	opt.action   = t->tcf_action;
729*4882a593Smuzhiyun 	opt.t_action = params->tcft_action;
730*4882a593Smuzhiyun 
731*4882a593Smuzhiyun 	if (nla_put(skb, TCA_TUNNEL_KEY_PARMS, sizeof(opt), &opt))
732*4882a593Smuzhiyun 		goto nla_put_failure;
733*4882a593Smuzhiyun 
734*4882a593Smuzhiyun 	if (params->tcft_action == TCA_TUNNEL_KEY_ACT_SET) {
735*4882a593Smuzhiyun 		struct ip_tunnel_info *info =
736*4882a593Smuzhiyun 			&params->tcft_enc_metadata->u.tun_info;
737*4882a593Smuzhiyun 		struct ip_tunnel_key *key = &info->key;
738*4882a593Smuzhiyun 		__be32 key_id = tunnel_id_to_key32(key->tun_id);
739*4882a593Smuzhiyun 
740*4882a593Smuzhiyun 		if (((key->tun_flags & TUNNEL_KEY) &&
741*4882a593Smuzhiyun 		     nla_put_be32(skb, TCA_TUNNEL_KEY_ENC_KEY_ID, key_id)) ||
742*4882a593Smuzhiyun 		    tunnel_key_dump_addresses(skb,
743*4882a593Smuzhiyun 					      &params->tcft_enc_metadata->u.tun_info) ||
744*4882a593Smuzhiyun 		    (key->tp_dst &&
745*4882a593Smuzhiyun 		      nla_put_be16(skb, TCA_TUNNEL_KEY_ENC_DST_PORT,
746*4882a593Smuzhiyun 				   key->tp_dst)) ||
747*4882a593Smuzhiyun 		    nla_put_u8(skb, TCA_TUNNEL_KEY_NO_CSUM,
748*4882a593Smuzhiyun 			       !(key->tun_flags & TUNNEL_CSUM)) ||
749*4882a593Smuzhiyun 		    tunnel_key_opts_dump(skb, info))
750*4882a593Smuzhiyun 			goto nla_put_failure;
751*4882a593Smuzhiyun 
752*4882a593Smuzhiyun 		if (key->tos && nla_put_u8(skb, TCA_TUNNEL_KEY_ENC_TOS, key->tos))
753*4882a593Smuzhiyun 			goto nla_put_failure;
754*4882a593Smuzhiyun 
755*4882a593Smuzhiyun 		if (key->ttl && nla_put_u8(skb, TCA_TUNNEL_KEY_ENC_TTL, key->ttl))
756*4882a593Smuzhiyun 			goto nla_put_failure;
757*4882a593Smuzhiyun 	}
758*4882a593Smuzhiyun 
759*4882a593Smuzhiyun 	tcf_tm_dump(&tm, &t->tcf_tm);
760*4882a593Smuzhiyun 	if (nla_put_64bit(skb, TCA_TUNNEL_KEY_TM, sizeof(tm),
761*4882a593Smuzhiyun 			  &tm, TCA_TUNNEL_KEY_PAD))
762*4882a593Smuzhiyun 		goto nla_put_failure;
763*4882a593Smuzhiyun 	spin_unlock_bh(&t->tcf_lock);
764*4882a593Smuzhiyun 
765*4882a593Smuzhiyun 	return skb->len;
766*4882a593Smuzhiyun 
767*4882a593Smuzhiyun nla_put_failure:
768*4882a593Smuzhiyun 	spin_unlock_bh(&t->tcf_lock);
769*4882a593Smuzhiyun 	nlmsg_trim(skb, b);
770*4882a593Smuzhiyun 	return -1;
771*4882a593Smuzhiyun }
772*4882a593Smuzhiyun 
tunnel_key_walker(struct net * net,struct sk_buff * skb,struct netlink_callback * cb,int type,const struct tc_action_ops * ops,struct netlink_ext_ack * extack)773*4882a593Smuzhiyun static int tunnel_key_walker(struct net *net, struct sk_buff *skb,
774*4882a593Smuzhiyun 			     struct netlink_callback *cb, int type,
775*4882a593Smuzhiyun 			     const struct tc_action_ops *ops,
776*4882a593Smuzhiyun 			     struct netlink_ext_ack *extack)
777*4882a593Smuzhiyun {
778*4882a593Smuzhiyun 	struct tc_action_net *tn = net_generic(net, tunnel_key_net_id);
779*4882a593Smuzhiyun 
780*4882a593Smuzhiyun 	return tcf_generic_walker(tn, skb, cb, type, ops, extack);
781*4882a593Smuzhiyun }
782*4882a593Smuzhiyun 
tunnel_key_search(struct net * net,struct tc_action ** a,u32 index)783*4882a593Smuzhiyun static int tunnel_key_search(struct net *net, struct tc_action **a, u32 index)
784*4882a593Smuzhiyun {
785*4882a593Smuzhiyun 	struct tc_action_net *tn = net_generic(net, tunnel_key_net_id);
786*4882a593Smuzhiyun 
787*4882a593Smuzhiyun 	return tcf_idr_search(tn, a, index);
788*4882a593Smuzhiyun }
789*4882a593Smuzhiyun 
790*4882a593Smuzhiyun static struct tc_action_ops act_tunnel_key_ops = {
791*4882a593Smuzhiyun 	.kind		=	"tunnel_key",
792*4882a593Smuzhiyun 	.id		=	TCA_ID_TUNNEL_KEY,
793*4882a593Smuzhiyun 	.owner		=	THIS_MODULE,
794*4882a593Smuzhiyun 	.act		=	tunnel_key_act,
795*4882a593Smuzhiyun 	.dump		=	tunnel_key_dump,
796*4882a593Smuzhiyun 	.init		=	tunnel_key_init,
797*4882a593Smuzhiyun 	.cleanup	=	tunnel_key_release,
798*4882a593Smuzhiyun 	.walk		=	tunnel_key_walker,
799*4882a593Smuzhiyun 	.lookup		=	tunnel_key_search,
800*4882a593Smuzhiyun 	.size		=	sizeof(struct tcf_tunnel_key),
801*4882a593Smuzhiyun };
802*4882a593Smuzhiyun 
tunnel_key_init_net(struct net * net)803*4882a593Smuzhiyun static __net_init int tunnel_key_init_net(struct net *net)
804*4882a593Smuzhiyun {
805*4882a593Smuzhiyun 	struct tc_action_net *tn = net_generic(net, tunnel_key_net_id);
806*4882a593Smuzhiyun 
807*4882a593Smuzhiyun 	return tc_action_net_init(net, tn, &act_tunnel_key_ops);
808*4882a593Smuzhiyun }
809*4882a593Smuzhiyun 
tunnel_key_exit_net(struct list_head * net_list)810*4882a593Smuzhiyun static void __net_exit tunnel_key_exit_net(struct list_head *net_list)
811*4882a593Smuzhiyun {
812*4882a593Smuzhiyun 	tc_action_net_exit(net_list, tunnel_key_net_id);
813*4882a593Smuzhiyun }
814*4882a593Smuzhiyun 
815*4882a593Smuzhiyun static struct pernet_operations tunnel_key_net_ops = {
816*4882a593Smuzhiyun 	.init = tunnel_key_init_net,
817*4882a593Smuzhiyun 	.exit_batch = tunnel_key_exit_net,
818*4882a593Smuzhiyun 	.id   = &tunnel_key_net_id,
819*4882a593Smuzhiyun 	.size = sizeof(struct tc_action_net),
820*4882a593Smuzhiyun };
821*4882a593Smuzhiyun 
tunnel_key_init_module(void)822*4882a593Smuzhiyun static int __init tunnel_key_init_module(void)
823*4882a593Smuzhiyun {
824*4882a593Smuzhiyun 	return tcf_register_action(&act_tunnel_key_ops, &tunnel_key_net_ops);
825*4882a593Smuzhiyun }
826*4882a593Smuzhiyun 
tunnel_key_cleanup_module(void)827*4882a593Smuzhiyun static void __exit tunnel_key_cleanup_module(void)
828*4882a593Smuzhiyun {
829*4882a593Smuzhiyun 	tcf_unregister_action(&act_tunnel_key_ops, &tunnel_key_net_ops);
830*4882a593Smuzhiyun }
831*4882a593Smuzhiyun 
832*4882a593Smuzhiyun module_init(tunnel_key_init_module);
833*4882a593Smuzhiyun module_exit(tunnel_key_cleanup_module);
834*4882a593Smuzhiyun 
835*4882a593Smuzhiyun MODULE_AUTHOR("Amir Vadai <amir@vadai.me>");
836*4882a593Smuzhiyun MODULE_DESCRIPTION("ip tunnel manipulation actions");
837*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
838