xref: /openbmc/linux/drivers/net/ethernet/netronome/nfp/flower/action.c (revision 28efb0046512e8a13ed9f9bdf0d68d10bbfbe9cf)
1 /*
2  * Copyright (C) 2017 Netronome Systems, Inc.
3  *
4  * This software is dual licensed under the GNU General License Version 2,
5  * June 1991 as shown in the file COPYING in the top-level directory of this
6  * source tree or the BSD 2-Clause License provided below.  You have the
7  * option to license this software under the complete terms of either license.
8  *
9  * The BSD 2-Clause License:
10  *
11  *     Redistribution and use in source and binary forms, with or
12  *     without modification, are permitted provided that the following
13  *     conditions are met:
14  *
15  *      1. Redistributions of source code must retain the above
16  *         copyright notice, this list of conditions and the following
17  *         disclaimer.
18  *
19  *      2. Redistributions in binary form must reproduce the above
20  *         copyright notice, this list of conditions and the following
21  *         disclaimer in the documentation and/or other materials
22  *         provided with the distribution.
23  *
24  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
28  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
29  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
30  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
31  * SOFTWARE.
32  */
33 
34 #include <linux/bitfield.h>
35 #include <net/pkt_cls.h>
36 #include <net/switchdev.h>
37 #include <net/tc_act/tc_gact.h>
38 #include <net/tc_act/tc_mirred.h>
39 #include <net/tc_act/tc_vlan.h>
40 #include <net/tc_act/tc_tunnel_key.h>
41 
42 #include "cmsg.h"
43 #include "main.h"
44 #include "../nfp_net_repr.h"
45 
46 static void nfp_fl_pop_vlan(struct nfp_fl_pop_vlan *pop_vlan)
47 {
48 	size_t act_size = sizeof(struct nfp_fl_pop_vlan);
49 	u16 tmp_pop_vlan_op;
50 
51 	tmp_pop_vlan_op =
52 		FIELD_PREP(NFP_FL_ACT_LEN_LW, act_size >> NFP_FL_LW_SIZ) |
53 		FIELD_PREP(NFP_FL_ACT_JMP_ID, NFP_FL_ACTION_OPCODE_POP_VLAN);
54 
55 	pop_vlan->a_op = cpu_to_be16(tmp_pop_vlan_op);
56 	pop_vlan->reserved = 0;
57 }
58 
59 static void
60 nfp_fl_push_vlan(struct nfp_fl_push_vlan *push_vlan,
61 		 const struct tc_action *action)
62 {
63 	size_t act_size = sizeof(struct nfp_fl_push_vlan);
64 	struct tcf_vlan *vlan = to_vlan(action);
65 	u16 tmp_push_vlan_tci;
66 	u16 tmp_push_vlan_op;
67 
68 	tmp_push_vlan_op =
69 		FIELD_PREP(NFP_FL_ACT_LEN_LW, act_size >> NFP_FL_LW_SIZ) |
70 		FIELD_PREP(NFP_FL_ACT_JMP_ID, NFP_FL_ACTION_OPCODE_PUSH_VLAN);
71 
72 	push_vlan->a_op = cpu_to_be16(tmp_push_vlan_op);
73 	/* Set action push vlan parameters. */
74 	push_vlan->reserved = 0;
75 	push_vlan->vlan_tpid = tcf_vlan_push_proto(action);
76 
77 	tmp_push_vlan_tci =
78 		FIELD_PREP(NFP_FL_PUSH_VLAN_PRIO, vlan->tcfv_push_prio) |
79 		FIELD_PREP(NFP_FL_PUSH_VLAN_VID, vlan->tcfv_push_vid) |
80 		NFP_FL_PUSH_VLAN_CFI;
81 	push_vlan->vlan_tci = cpu_to_be16(tmp_push_vlan_tci);
82 }
83 
84 static bool nfp_fl_netdev_is_tunnel_type(struct net_device *out_dev,
85 					 enum nfp_flower_tun_type tun_type)
86 {
87 	if (!out_dev->rtnl_link_ops)
88 		return false;
89 
90 	if (!strcmp(out_dev->rtnl_link_ops->kind, "vxlan"))
91 		return tun_type == NFP_FL_TUNNEL_VXLAN;
92 
93 	return false;
94 }
95 
96 static int
97 nfp_fl_output(struct nfp_fl_output *output, const struct tc_action *action,
98 	      struct nfp_fl_payload *nfp_flow, bool last,
99 	      struct net_device *in_dev, enum nfp_flower_tun_type tun_type,
100 	      int *tun_out_cnt)
101 {
102 	size_t act_size = sizeof(struct nfp_fl_output);
103 	u16 tmp_output_op, tmp_flags;
104 	struct net_device *out_dev;
105 	int ifindex;
106 
107 	/* Set action opcode to output action. */
108 	tmp_output_op =
109 		FIELD_PREP(NFP_FL_ACT_LEN_LW, act_size >> NFP_FL_LW_SIZ) |
110 		FIELD_PREP(NFP_FL_ACT_JMP_ID, NFP_FL_ACTION_OPCODE_OUTPUT);
111 
112 	output->a_op = cpu_to_be16(tmp_output_op);
113 
114 	ifindex = tcf_mirred_ifindex(action);
115 	out_dev = __dev_get_by_index(dev_net(in_dev), ifindex);
116 	if (!out_dev)
117 		return -EOPNOTSUPP;
118 
119 	tmp_flags = last ? NFP_FL_OUT_FLAGS_LAST : 0;
120 
121 	if (tun_type) {
122 		/* Verify the egress netdev matches the tunnel type. */
123 		if (!nfp_fl_netdev_is_tunnel_type(out_dev, tun_type))
124 			return -EOPNOTSUPP;
125 
126 		if (*tun_out_cnt)
127 			return -EOPNOTSUPP;
128 		(*tun_out_cnt)++;
129 
130 		output->flags = cpu_to_be16(tmp_flags |
131 					    NFP_FL_OUT_FLAGS_USE_TUN);
132 		output->port = cpu_to_be32(NFP_FL_PORT_TYPE_TUN | tun_type);
133 	} else {
134 		/* Set action output parameters. */
135 		output->flags = cpu_to_be16(tmp_flags);
136 
137 		/* Only offload if egress ports are on the same device as the
138 		 * ingress port.
139 		 */
140 		if (!switchdev_port_same_parent_id(in_dev, out_dev))
141 			return -EOPNOTSUPP;
142 
143 		output->port = cpu_to_be32(nfp_repr_get_port_id(out_dev));
144 		if (!output->port)
145 			return -EOPNOTSUPP;
146 	}
147 	nfp_flow->meta.shortcut = output->port;
148 
149 	return 0;
150 }
151 
152 static bool nfp_fl_supported_tun_port(const struct tc_action *action)
153 {
154 	struct ip_tunnel_info *tun = tcf_tunnel_info(action);
155 
156 	return tun->key.tp_dst == htons(NFP_FL_VXLAN_PORT);
157 }
158 
159 static struct nfp_fl_pre_tunnel *nfp_fl_pre_tunnel(char *act_data, int act_len)
160 {
161 	size_t act_size = sizeof(struct nfp_fl_pre_tunnel);
162 	struct nfp_fl_pre_tunnel *pre_tun_act;
163 	u16 tmp_pre_tun_op;
164 
165 	/* Pre_tunnel action must be first on action list.
166 	 * If other actions already exist they need pushed forward.
167 	 */
168 	if (act_len)
169 		memmove(act_data + act_size, act_data, act_len);
170 
171 	pre_tun_act = (struct nfp_fl_pre_tunnel *)act_data;
172 
173 	memset(pre_tun_act, 0, act_size);
174 
175 	tmp_pre_tun_op =
176 		FIELD_PREP(NFP_FL_ACT_LEN_LW, act_size >> NFP_FL_LW_SIZ) |
177 		FIELD_PREP(NFP_FL_ACT_JMP_ID, NFP_FL_ACTION_OPCODE_PRE_TUNNEL);
178 
179 	pre_tun_act->a_op = cpu_to_be16(tmp_pre_tun_op);
180 
181 	return pre_tun_act;
182 }
183 
184 static int
185 nfp_fl_set_vxlan(struct nfp_fl_set_vxlan *set_vxlan,
186 		 const struct tc_action *action,
187 		 struct nfp_fl_pre_tunnel *pre_tun)
188 {
189 	struct ip_tunnel_info *vxlan = tcf_tunnel_info(action);
190 	size_t act_size = sizeof(struct nfp_fl_set_vxlan);
191 	u32 tmp_set_vxlan_type_index = 0;
192 	u16 tmp_set_vxlan_op;
193 	/* Currently support one pre-tunnel so index is always 0. */
194 	int pretun_idx = 0;
195 
196 	if (vxlan->options_len) {
197 		/* Do not support options e.g. vxlan gpe. */
198 		return -EOPNOTSUPP;
199 	}
200 
201 	tmp_set_vxlan_op =
202 		FIELD_PREP(NFP_FL_ACT_LEN_LW, act_size >> NFP_FL_LW_SIZ) |
203 		FIELD_PREP(NFP_FL_ACT_JMP_ID,
204 			   NFP_FL_ACTION_OPCODE_SET_IPV4_TUNNEL);
205 
206 	set_vxlan->a_op = cpu_to_be16(tmp_set_vxlan_op);
207 
208 	/* Set tunnel type and pre-tunnel index. */
209 	tmp_set_vxlan_type_index |=
210 		FIELD_PREP(NFP_FL_IPV4_TUNNEL_TYPE, NFP_FL_TUNNEL_VXLAN) |
211 		FIELD_PREP(NFP_FL_IPV4_PRE_TUN_INDEX, pretun_idx);
212 
213 	set_vxlan->tun_type_index = cpu_to_be32(tmp_set_vxlan_type_index);
214 
215 	set_vxlan->tun_id = vxlan->key.tun_id;
216 	set_vxlan->tun_flags = vxlan->key.tun_flags;
217 	set_vxlan->ipv4_ttl = vxlan->key.ttl;
218 	set_vxlan->ipv4_tos = vxlan->key.tos;
219 
220 	/* Complete pre_tunnel action. */
221 	pre_tun->ipv4_dst = vxlan->key.u.ipv4.dst;
222 
223 	return 0;
224 }
225 
226 static int
227 nfp_flower_loop_action(const struct tc_action *a,
228 		       struct nfp_fl_payload *nfp_fl, int *a_len,
229 		       struct net_device *netdev,
230 		       enum nfp_flower_tun_type *tun_type, int *tun_out_cnt)
231 {
232 	struct nfp_fl_pre_tunnel *pre_tun;
233 	struct nfp_fl_set_vxlan *s_vxl;
234 	struct nfp_fl_push_vlan *psh_v;
235 	struct nfp_fl_pop_vlan *pop_v;
236 	struct nfp_fl_output *output;
237 	int err;
238 
239 	if (is_tcf_gact_shot(a)) {
240 		nfp_fl->meta.shortcut = cpu_to_be32(NFP_FL_SC_ACT_DROP);
241 	} else if (is_tcf_mirred_egress_redirect(a)) {
242 		if (*a_len + sizeof(struct nfp_fl_output) > NFP_FL_MAX_A_SIZ)
243 			return -EOPNOTSUPP;
244 
245 		output = (struct nfp_fl_output *)&nfp_fl->action_data[*a_len];
246 		err = nfp_fl_output(output, a, nfp_fl, true, netdev, *tun_type,
247 				    tun_out_cnt);
248 		if (err)
249 			return err;
250 
251 		*a_len += sizeof(struct nfp_fl_output);
252 	} else if (is_tcf_mirred_egress_mirror(a)) {
253 		if (*a_len + sizeof(struct nfp_fl_output) > NFP_FL_MAX_A_SIZ)
254 			return -EOPNOTSUPP;
255 
256 		output = (struct nfp_fl_output *)&nfp_fl->action_data[*a_len];
257 		err = nfp_fl_output(output, a, nfp_fl, false, netdev, *tun_type,
258 				    tun_out_cnt);
259 		if (err)
260 			return err;
261 
262 		*a_len += sizeof(struct nfp_fl_output);
263 	} else if (is_tcf_vlan(a) && tcf_vlan_action(a) == TCA_VLAN_ACT_POP) {
264 		if (*a_len + sizeof(struct nfp_fl_pop_vlan) > NFP_FL_MAX_A_SIZ)
265 			return -EOPNOTSUPP;
266 
267 		pop_v = (struct nfp_fl_pop_vlan *)&nfp_fl->action_data[*a_len];
268 		nfp_fl->meta.shortcut = cpu_to_be32(NFP_FL_SC_ACT_POPV);
269 
270 		nfp_fl_pop_vlan(pop_v);
271 		*a_len += sizeof(struct nfp_fl_pop_vlan);
272 	} else if (is_tcf_vlan(a) && tcf_vlan_action(a) == TCA_VLAN_ACT_PUSH) {
273 		if (*a_len + sizeof(struct nfp_fl_push_vlan) > NFP_FL_MAX_A_SIZ)
274 			return -EOPNOTSUPP;
275 
276 		psh_v = (struct nfp_fl_push_vlan *)&nfp_fl->action_data[*a_len];
277 		nfp_fl->meta.shortcut = cpu_to_be32(NFP_FL_SC_ACT_NULL);
278 
279 		nfp_fl_push_vlan(psh_v, a);
280 		*a_len += sizeof(struct nfp_fl_push_vlan);
281 	} else if (is_tcf_tunnel_set(a) && nfp_fl_supported_tun_port(a)) {
282 		/* Pre-tunnel action is required for tunnel encap.
283 		 * This checks for next hop entries on NFP.
284 		 * If none, the packet falls back before applying other actions.
285 		 */
286 		if (*a_len + sizeof(struct nfp_fl_pre_tunnel) +
287 		    sizeof(struct nfp_fl_set_vxlan) > NFP_FL_MAX_A_SIZ)
288 			return -EOPNOTSUPP;
289 
290 		*tun_type = NFP_FL_TUNNEL_VXLAN;
291 		pre_tun = nfp_fl_pre_tunnel(nfp_fl->action_data, *a_len);
292 		nfp_fl->meta.shortcut = cpu_to_be32(NFP_FL_SC_ACT_NULL);
293 		*a_len += sizeof(struct nfp_fl_pre_tunnel);
294 
295 		s_vxl = (struct nfp_fl_set_vxlan *)&nfp_fl->action_data[*a_len];
296 		err = nfp_fl_set_vxlan(s_vxl, a, pre_tun);
297 		if (err)
298 			return err;
299 
300 		*a_len += sizeof(struct nfp_fl_set_vxlan);
301 	} else if (is_tcf_tunnel_release(a)) {
302 		/* Tunnel decap is handled by default so accept action. */
303 		return 0;
304 	} else {
305 		/* Currently we do not handle any other actions. */
306 		return -EOPNOTSUPP;
307 	}
308 
309 	return 0;
310 }
311 
312 int nfp_flower_compile_action(struct tc_cls_flower_offload *flow,
313 			      struct net_device *netdev,
314 			      struct nfp_fl_payload *nfp_flow)
315 {
316 	int act_len, act_cnt, err, tun_out_cnt;
317 	enum nfp_flower_tun_type tun_type;
318 	const struct tc_action *a;
319 	LIST_HEAD(actions);
320 
321 	memset(nfp_flow->action_data, 0, NFP_FL_MAX_A_SIZ);
322 	nfp_flow->meta.act_len = 0;
323 	tun_type = NFP_FL_TUNNEL_NONE;
324 	act_len = 0;
325 	act_cnt = 0;
326 	tun_out_cnt = 0;
327 
328 	tcf_exts_to_list(flow->exts, &actions);
329 	list_for_each_entry(a, &actions, list) {
330 		err = nfp_flower_loop_action(a, nfp_flow, &act_len, netdev,
331 					     &tun_type, &tun_out_cnt);
332 		if (err)
333 			return err;
334 		act_cnt++;
335 	}
336 
337 	/* We optimise when the action list is small, this can unfortunately
338 	 * not happen once we have more than one action in the action list.
339 	 */
340 	if (act_cnt > 1)
341 		nfp_flow->meta.shortcut = cpu_to_be32(NFP_FL_SC_ACT_NULL);
342 
343 	nfp_flow->meta.act_len = act_len;
344 
345 	return 0;
346 }
347