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(¶ms->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 ¶ms->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 ¶ms->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