1 /*
2  * Copyright (c) 2016, Mellanox Technologies. All rights reserved.
3  *
4  * This software is available to you under a choice of one of two
5  * licenses.  You may choose to be licensed under the terms of the GNU
6  * General Public License (GPL) Version 2, available from the file
7  * COPYING in the main directory of this source tree, or the
8  * OpenIB.org BSD license below:
9  *
10  *     Redistribution and use in source and binary forms, with or
11  *     without modification, are permitted provided that the following
12  *     conditions are met:
13  *
14  *      - Redistributions of source code must retain the above
15  *        copyright notice, this list of conditions and the following
16  *        disclaimer.
17  *
18  *      - Redistributions in binary form must reproduce the above
19  *        copyright notice, this list of conditions and the following
20  *        disclaimer in the documentation and/or other materials
21  *        provided with the distribution.
22  *
23  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
27  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30  * SOFTWARE.
31  */
32 
33 #include <linux/mlx5/fs.h>
34 #include "en.h"
35 #include "en/params.h"
36 #include "en/xsk/pool.h"
37 
38 struct mlx5e_ethtool_rule {
39 	struct list_head             list;
40 	struct ethtool_rx_flow_spec  flow_spec;
41 	struct mlx5_flow_handle	     *rule;
42 	struct mlx5e_ethtool_table   *eth_ft;
43 };
44 
put_flow_table(struct mlx5e_ethtool_table * eth_ft)45 static void put_flow_table(struct mlx5e_ethtool_table *eth_ft)
46 {
47 	if (!--eth_ft->num_rules) {
48 		mlx5_destroy_flow_table(eth_ft->ft);
49 		eth_ft->ft = NULL;
50 	}
51 }
52 
53 #define MLX5E_ETHTOOL_L3_L4_PRIO 0
54 #define MLX5E_ETHTOOL_L2_PRIO (MLX5E_ETHTOOL_L3_L4_PRIO + ETHTOOL_NUM_L3_L4_FTS)
55 #define MLX5E_ETHTOOL_NUM_ENTRIES 64000
56 #define MLX5E_ETHTOOL_NUM_GROUPS  10
get_flow_table(struct mlx5e_priv * priv,struct ethtool_rx_flow_spec * fs,int num_tuples)57 static struct mlx5e_ethtool_table *get_flow_table(struct mlx5e_priv *priv,
58 						  struct ethtool_rx_flow_spec *fs,
59 						  int num_tuples)
60 {
61 	struct mlx5_flow_table_attr ft_attr = {};
62 	struct mlx5e_ethtool_table *eth_ft;
63 	struct mlx5_flow_namespace *ns;
64 	struct mlx5_flow_table *ft;
65 	int max_tuples;
66 	int table_size;
67 	int prio;
68 
69 	switch (fs->flow_type & ~(FLOW_EXT | FLOW_MAC_EXT)) {
70 	case TCP_V4_FLOW:
71 	case UDP_V4_FLOW:
72 	case TCP_V6_FLOW:
73 	case UDP_V6_FLOW:
74 		max_tuples = ETHTOOL_NUM_L3_L4_FTS;
75 		prio = MLX5E_ETHTOOL_L3_L4_PRIO + (max_tuples - num_tuples);
76 		eth_ft = &priv->fs.ethtool.l3_l4_ft[prio];
77 		break;
78 	case IP_USER_FLOW:
79 	case IPV6_USER_FLOW:
80 		max_tuples = ETHTOOL_NUM_L3_L4_FTS;
81 		prio = MLX5E_ETHTOOL_L3_L4_PRIO + (max_tuples - num_tuples);
82 		eth_ft = &priv->fs.ethtool.l3_l4_ft[prio];
83 		break;
84 	case ETHER_FLOW:
85 		max_tuples = ETHTOOL_NUM_L2_FTS;
86 		prio = max_tuples - num_tuples;
87 		eth_ft = &priv->fs.ethtool.l2_ft[prio];
88 		prio += MLX5E_ETHTOOL_L2_PRIO;
89 		break;
90 	default:
91 		return ERR_PTR(-EINVAL);
92 	}
93 
94 	eth_ft->num_rules++;
95 	if (eth_ft->ft)
96 		return eth_ft;
97 
98 	ns = mlx5_get_flow_namespace(priv->mdev,
99 				     MLX5_FLOW_NAMESPACE_ETHTOOL);
100 	if (!ns)
101 		return ERR_PTR(-EOPNOTSUPP);
102 
103 	table_size = min_t(u32, BIT(MLX5_CAP_FLOWTABLE(priv->mdev,
104 						       flow_table_properties_nic_receive.log_max_ft_size)),
105 			   MLX5E_ETHTOOL_NUM_ENTRIES);
106 
107 	ft_attr.prio = prio;
108 	ft_attr.max_fte = table_size;
109 	ft_attr.autogroup.max_num_groups = MLX5E_ETHTOOL_NUM_GROUPS;
110 	ft = mlx5_create_auto_grouped_flow_table(ns, &ft_attr);
111 	if (IS_ERR(ft))
112 		return (void *)ft;
113 
114 	eth_ft->ft = ft;
115 	return eth_ft;
116 }
117 
mask_spec(u8 * mask,u8 * val,size_t size)118 static void mask_spec(u8 *mask, u8 *val, size_t size)
119 {
120 	unsigned int i;
121 
122 	for (i = 0; i < size; i++, mask++, val++)
123 		*((u8 *)val) = *((u8 *)mask) & *((u8 *)val);
124 }
125 
126 #define MLX5E_FTE_SET(header_p, fld, v)  \
127 	MLX5_SET(fte_match_set_lyr_2_4, header_p, fld, v)
128 
129 #define MLX5E_FTE_ADDR_OF(header_p, fld) \
130 	MLX5_ADDR_OF(fte_match_set_lyr_2_4, header_p, fld)
131 
132 static void
set_ip4(void * headers_c,void * headers_v,__be32 ip4src_m,__be32 ip4src_v,__be32 ip4dst_m,__be32 ip4dst_v)133 set_ip4(void *headers_c, void *headers_v, __be32 ip4src_m,
134 	__be32 ip4src_v, __be32 ip4dst_m, __be32 ip4dst_v)
135 {
136 	if (ip4src_m) {
137 		memcpy(MLX5E_FTE_ADDR_OF(headers_v, src_ipv4_src_ipv6.ipv4_layout.ipv4),
138 		       &ip4src_v, sizeof(ip4src_v));
139 		memcpy(MLX5E_FTE_ADDR_OF(headers_c, src_ipv4_src_ipv6.ipv4_layout.ipv4),
140 		       &ip4src_m, sizeof(ip4src_m));
141 	}
142 	if (ip4dst_m) {
143 		memcpy(MLX5E_FTE_ADDR_OF(headers_v, dst_ipv4_dst_ipv6.ipv4_layout.ipv4),
144 		       &ip4dst_v, sizeof(ip4dst_v));
145 		memcpy(MLX5E_FTE_ADDR_OF(headers_c, dst_ipv4_dst_ipv6.ipv4_layout.ipv4),
146 		       &ip4dst_m, sizeof(ip4dst_m));
147 	}
148 
149 	MLX5E_FTE_SET(headers_c, ethertype, 0xffff);
150 	MLX5E_FTE_SET(headers_v, ethertype, ETH_P_IP);
151 }
152 
153 static void
set_ip6(void * headers_c,void * headers_v,__be32 ip6src_m[4],__be32 ip6src_v[4],__be32 ip6dst_m[4],__be32 ip6dst_v[4])154 set_ip6(void *headers_c, void *headers_v, __be32 ip6src_m[4],
155 	__be32 ip6src_v[4], __be32 ip6dst_m[4], __be32 ip6dst_v[4])
156 {
157 	u8 ip6_sz = MLX5_FLD_SZ_BYTES(ipv6_layout, ipv6);
158 
159 	if (!ipv6_addr_any((struct in6_addr *)ip6src_m)) {
160 		memcpy(MLX5E_FTE_ADDR_OF(headers_v, src_ipv4_src_ipv6.ipv6_layout.ipv6),
161 		       ip6src_v, ip6_sz);
162 		memcpy(MLX5E_FTE_ADDR_OF(headers_c, src_ipv4_src_ipv6.ipv6_layout.ipv6),
163 		       ip6src_m, ip6_sz);
164 	}
165 	if (!ipv6_addr_any((struct in6_addr *)ip6dst_m)) {
166 		memcpy(MLX5E_FTE_ADDR_OF(headers_v, dst_ipv4_dst_ipv6.ipv6_layout.ipv6),
167 		       ip6dst_v, ip6_sz);
168 		memcpy(MLX5E_FTE_ADDR_OF(headers_c, dst_ipv4_dst_ipv6.ipv6_layout.ipv6),
169 		       ip6dst_m, ip6_sz);
170 	}
171 
172 	MLX5E_FTE_SET(headers_c, ethertype, 0xffff);
173 	MLX5E_FTE_SET(headers_v, ethertype, ETH_P_IPV6);
174 }
175 
176 static void
set_tcp(void * headers_c,void * headers_v,__be16 psrc_m,__be16 psrc_v,__be16 pdst_m,__be16 pdst_v)177 set_tcp(void *headers_c, void *headers_v, __be16 psrc_m, __be16 psrc_v,
178 	__be16 pdst_m, __be16 pdst_v)
179 {
180 	if (psrc_m) {
181 		MLX5E_FTE_SET(headers_c, tcp_sport, ntohs(psrc_m));
182 		MLX5E_FTE_SET(headers_v, tcp_sport, ntohs(psrc_v));
183 	}
184 	if (pdst_m) {
185 		MLX5E_FTE_SET(headers_c, tcp_dport, ntohs(pdst_m));
186 		MLX5E_FTE_SET(headers_v, tcp_dport, ntohs(pdst_v));
187 	}
188 
189 	MLX5E_FTE_SET(headers_c, ip_protocol, 0xffff);
190 	MLX5E_FTE_SET(headers_v, ip_protocol, IPPROTO_TCP);
191 }
192 
193 static void
set_udp(void * headers_c,void * headers_v,__be16 psrc_m,__be16 psrc_v,__be16 pdst_m,__be16 pdst_v)194 set_udp(void *headers_c, void *headers_v, __be16 psrc_m, __be16 psrc_v,
195 	__be16 pdst_m, __be16 pdst_v)
196 {
197 	if (psrc_m) {
198 		MLX5E_FTE_SET(headers_c, udp_sport, ntohs(psrc_m));
199 		MLX5E_FTE_SET(headers_v, udp_sport, ntohs(psrc_v));
200 	}
201 
202 	if (pdst_m) {
203 		MLX5E_FTE_SET(headers_c, udp_dport, ntohs(pdst_m));
204 		MLX5E_FTE_SET(headers_v, udp_dport, ntohs(pdst_v));
205 	}
206 
207 	MLX5E_FTE_SET(headers_c, ip_protocol, 0xffff);
208 	MLX5E_FTE_SET(headers_v, ip_protocol, IPPROTO_UDP);
209 }
210 
211 static void
parse_tcp4(void * headers_c,void * headers_v,struct ethtool_rx_flow_spec * fs)212 parse_tcp4(void *headers_c, void *headers_v, struct ethtool_rx_flow_spec *fs)
213 {
214 	struct ethtool_tcpip4_spec *l4_mask = &fs->m_u.tcp_ip4_spec;
215 	struct ethtool_tcpip4_spec *l4_val  = &fs->h_u.tcp_ip4_spec;
216 
217 	set_ip4(headers_c, headers_v, l4_mask->ip4src, l4_val->ip4src,
218 		l4_mask->ip4dst, l4_val->ip4dst);
219 
220 	set_tcp(headers_c, headers_v, l4_mask->psrc, l4_val->psrc,
221 		l4_mask->pdst, l4_val->pdst);
222 }
223 
224 static void
parse_udp4(void * headers_c,void * headers_v,struct ethtool_rx_flow_spec * fs)225 parse_udp4(void *headers_c, void *headers_v, struct ethtool_rx_flow_spec *fs)
226 {
227 	struct ethtool_tcpip4_spec *l4_mask = &fs->m_u.udp_ip4_spec;
228 	struct ethtool_tcpip4_spec *l4_val  = &fs->h_u.udp_ip4_spec;
229 
230 	set_ip4(headers_c, headers_v, l4_mask->ip4src, l4_val->ip4src,
231 		l4_mask->ip4dst, l4_val->ip4dst);
232 
233 	set_udp(headers_c, headers_v, l4_mask->psrc, l4_val->psrc,
234 		l4_mask->pdst, l4_val->pdst);
235 }
236 
237 static void
parse_ip4(void * headers_c,void * headers_v,struct ethtool_rx_flow_spec * fs)238 parse_ip4(void *headers_c, void *headers_v, struct ethtool_rx_flow_spec *fs)
239 {
240 	struct ethtool_usrip4_spec *l3_mask = &fs->m_u.usr_ip4_spec;
241 	struct ethtool_usrip4_spec *l3_val  = &fs->h_u.usr_ip4_spec;
242 
243 	set_ip4(headers_c, headers_v, l3_mask->ip4src, l3_val->ip4src,
244 		l3_mask->ip4dst, l3_val->ip4dst);
245 
246 	if (l3_mask->proto) {
247 		MLX5E_FTE_SET(headers_c, ip_protocol, l3_mask->proto);
248 		MLX5E_FTE_SET(headers_v, ip_protocol, l3_val->proto);
249 	}
250 }
251 
252 static void
parse_ip6(void * headers_c,void * headers_v,struct ethtool_rx_flow_spec * fs)253 parse_ip6(void *headers_c, void *headers_v, struct ethtool_rx_flow_spec *fs)
254 {
255 	struct ethtool_usrip6_spec *l3_mask = &fs->m_u.usr_ip6_spec;
256 	struct ethtool_usrip6_spec *l3_val  = &fs->h_u.usr_ip6_spec;
257 
258 	set_ip6(headers_c, headers_v, l3_mask->ip6src,
259 		l3_val->ip6src, l3_mask->ip6dst, l3_val->ip6dst);
260 
261 	if (l3_mask->l4_proto) {
262 		MLX5E_FTE_SET(headers_c, ip_protocol, l3_mask->l4_proto);
263 		MLX5E_FTE_SET(headers_v, ip_protocol, l3_val->l4_proto);
264 	}
265 }
266 
267 static void
parse_tcp6(void * headers_c,void * headers_v,struct ethtool_rx_flow_spec * fs)268 parse_tcp6(void *headers_c, void *headers_v, struct ethtool_rx_flow_spec *fs)
269 {
270 	struct ethtool_tcpip6_spec *l4_mask = &fs->m_u.tcp_ip6_spec;
271 	struct ethtool_tcpip6_spec *l4_val  = &fs->h_u.tcp_ip6_spec;
272 
273 	set_ip6(headers_c, headers_v, l4_mask->ip6src,
274 		l4_val->ip6src, l4_mask->ip6dst, l4_val->ip6dst);
275 
276 	set_tcp(headers_c, headers_v, l4_mask->psrc, l4_val->psrc,
277 		l4_mask->pdst, l4_val->pdst);
278 }
279 
280 static void
parse_udp6(void * headers_c,void * headers_v,struct ethtool_rx_flow_spec * fs)281 parse_udp6(void *headers_c, void *headers_v, struct ethtool_rx_flow_spec *fs)
282 {
283 	struct ethtool_tcpip6_spec *l4_mask = &fs->m_u.udp_ip6_spec;
284 	struct ethtool_tcpip6_spec *l4_val  = &fs->h_u.udp_ip6_spec;
285 
286 	set_ip6(headers_c, headers_v, l4_mask->ip6src,
287 		l4_val->ip6src, l4_mask->ip6dst, l4_val->ip6dst);
288 
289 	set_udp(headers_c, headers_v, l4_mask->psrc, l4_val->psrc,
290 		l4_mask->pdst, l4_val->pdst);
291 }
292 
293 static void
parse_ether(void * headers_c,void * headers_v,struct ethtool_rx_flow_spec * fs)294 parse_ether(void *headers_c, void *headers_v, struct ethtool_rx_flow_spec *fs)
295 {
296 	struct ethhdr *eth_mask = &fs->m_u.ether_spec;
297 	struct ethhdr *eth_val = &fs->h_u.ether_spec;
298 
299 	mask_spec((u8 *)eth_mask, (u8 *)eth_val, sizeof(*eth_mask));
300 	ether_addr_copy(MLX5E_FTE_ADDR_OF(headers_c, smac_47_16), eth_mask->h_source);
301 	ether_addr_copy(MLX5E_FTE_ADDR_OF(headers_v, smac_47_16), eth_val->h_source);
302 	ether_addr_copy(MLX5E_FTE_ADDR_OF(headers_c, dmac_47_16), eth_mask->h_dest);
303 	ether_addr_copy(MLX5E_FTE_ADDR_OF(headers_v, dmac_47_16), eth_val->h_dest);
304 	MLX5E_FTE_SET(headers_c, ethertype, ntohs(eth_mask->h_proto));
305 	MLX5E_FTE_SET(headers_v, ethertype, ntohs(eth_val->h_proto));
306 }
307 
308 static void
set_cvlan(void * headers_c,void * headers_v,__be16 vlan_tci)309 set_cvlan(void *headers_c, void *headers_v, __be16 vlan_tci)
310 {
311 	MLX5E_FTE_SET(headers_c, cvlan_tag, 1);
312 	MLX5E_FTE_SET(headers_v, cvlan_tag, 1);
313 	MLX5E_FTE_SET(headers_c, first_vid, 0xfff);
314 	MLX5E_FTE_SET(headers_v, first_vid, ntohs(vlan_tci));
315 }
316 
317 static void
set_dmac(void * headers_c,void * headers_v,unsigned char m_dest[ETH_ALEN],unsigned char v_dest[ETH_ALEN])318 set_dmac(void *headers_c, void *headers_v,
319 	 unsigned char m_dest[ETH_ALEN], unsigned char v_dest[ETH_ALEN])
320 {
321 	ether_addr_copy(MLX5E_FTE_ADDR_OF(headers_c, dmac_47_16), m_dest);
322 	ether_addr_copy(MLX5E_FTE_ADDR_OF(headers_v, dmac_47_16), v_dest);
323 }
324 
set_flow_attrs(u32 * match_c,u32 * match_v,struct ethtool_rx_flow_spec * fs)325 static int set_flow_attrs(u32 *match_c, u32 *match_v,
326 			  struct ethtool_rx_flow_spec *fs)
327 {
328 	void *outer_headers_c = MLX5_ADDR_OF(fte_match_param, match_c,
329 					     outer_headers);
330 	void *outer_headers_v = MLX5_ADDR_OF(fte_match_param, match_v,
331 					     outer_headers);
332 	u32 flow_type = fs->flow_type & ~(FLOW_EXT | FLOW_MAC_EXT);
333 
334 	switch (flow_type) {
335 	case TCP_V4_FLOW:
336 		parse_tcp4(outer_headers_c, outer_headers_v, fs);
337 		break;
338 	case UDP_V4_FLOW:
339 		parse_udp4(outer_headers_c, outer_headers_v, fs);
340 		break;
341 	case IP_USER_FLOW:
342 		parse_ip4(outer_headers_c, outer_headers_v, fs);
343 		break;
344 	case TCP_V6_FLOW:
345 		parse_tcp6(outer_headers_c, outer_headers_v, fs);
346 		break;
347 	case UDP_V6_FLOW:
348 		parse_udp6(outer_headers_c, outer_headers_v, fs);
349 		break;
350 	case IPV6_USER_FLOW:
351 		parse_ip6(outer_headers_c, outer_headers_v, fs);
352 		break;
353 	case ETHER_FLOW:
354 		parse_ether(outer_headers_c, outer_headers_v, fs);
355 		break;
356 	default:
357 		return -EINVAL;
358 	}
359 
360 	if ((fs->flow_type & FLOW_EXT) &&
361 	    (fs->m_ext.vlan_tci & cpu_to_be16(VLAN_VID_MASK)))
362 		set_cvlan(outer_headers_c, outer_headers_v, fs->h_ext.vlan_tci);
363 
364 	if (fs->flow_type & FLOW_MAC_EXT &&
365 	    !is_zero_ether_addr(fs->m_ext.h_dest)) {
366 		mask_spec(fs->m_ext.h_dest, fs->h_ext.h_dest, ETH_ALEN);
367 		set_dmac(outer_headers_c, outer_headers_v, fs->m_ext.h_dest,
368 			 fs->h_ext.h_dest);
369 	}
370 
371 	return 0;
372 }
373 
add_rule_to_list(struct mlx5e_priv * priv,struct mlx5e_ethtool_rule * rule)374 static void add_rule_to_list(struct mlx5e_priv *priv,
375 			     struct mlx5e_ethtool_rule *rule)
376 {
377 	struct mlx5e_ethtool_rule *iter;
378 	struct list_head *head = &priv->fs.ethtool.rules;
379 
380 	list_for_each_entry(iter, &priv->fs.ethtool.rules, list) {
381 		if (iter->flow_spec.location > rule->flow_spec.location)
382 			break;
383 		head = &iter->list;
384 	}
385 	priv->fs.ethtool.tot_num_rules++;
386 	list_add(&rule->list, head);
387 }
388 
outer_header_zero(u32 * match_criteria)389 static bool outer_header_zero(u32 *match_criteria)
390 {
391 	int size = MLX5_FLD_SZ_BYTES(fte_match_param, outer_headers);
392 	char *outer_headers_c = MLX5_ADDR_OF(fte_match_param, match_criteria,
393 					     outer_headers);
394 
395 	return outer_headers_c[0] == 0 && !memcmp(outer_headers_c,
396 						  outer_headers_c + 1,
397 						  size - 1);
398 }
399 
400 static struct mlx5_flow_handle *
add_ethtool_flow_rule(struct mlx5e_priv * priv,struct mlx5_flow_table * ft,struct ethtool_rx_flow_spec * fs)401 add_ethtool_flow_rule(struct mlx5e_priv *priv,
402 		      struct mlx5_flow_table *ft,
403 		      struct ethtool_rx_flow_spec *fs)
404 {
405 	struct mlx5_flow_act flow_act = { .flags = FLOW_ACT_NO_APPEND };
406 	struct mlx5_flow_destination *dst = NULL;
407 	struct mlx5_flow_handle *rule;
408 	struct mlx5_flow_spec *spec;
409 	int err = 0;
410 
411 	spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
412 	if (!spec)
413 		return ERR_PTR(-ENOMEM);
414 	err = set_flow_attrs(spec->match_criteria, spec->match_value,
415 			     fs);
416 	if (err)
417 		goto free;
418 
419 	if (fs->ring_cookie == RX_CLS_FLOW_DISC) {
420 		flow_act.action = MLX5_FLOW_CONTEXT_ACTION_DROP;
421 	} else {
422 		struct mlx5e_params *params = &priv->channels.params;
423 		enum mlx5e_rq_group group;
424 		struct mlx5e_tir *tir;
425 		u16 ix;
426 
427 		mlx5e_qid_get_ch_and_group(params, fs->ring_cookie, &ix, &group);
428 		tir = group == MLX5E_RQ_GROUP_XSK ? priv->xsk_tir : priv->direct_tir;
429 
430 		dst = kzalloc(sizeof(*dst), GFP_KERNEL);
431 		if (!dst) {
432 			err = -ENOMEM;
433 			goto free;
434 		}
435 
436 		dst->type = MLX5_FLOW_DESTINATION_TYPE_TIR;
437 		dst->tir_num = tir[ix].tirn;
438 		flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
439 	}
440 
441 	spec->match_criteria_enable = (!outer_header_zero(spec->match_criteria));
442 	spec->flow_context.flow_tag = MLX5_FS_DEFAULT_FLOW_TAG;
443 	rule = mlx5_add_flow_rules(ft, spec, &flow_act, dst, dst ? 1 : 0);
444 	if (IS_ERR(rule)) {
445 		err = PTR_ERR(rule);
446 		netdev_err(priv->netdev, "%s: failed to add ethtool steering rule: %d\n",
447 			   __func__, err);
448 		goto free;
449 	}
450 free:
451 	kvfree(spec);
452 	kfree(dst);
453 	return err ? ERR_PTR(err) : rule;
454 }
455 
del_ethtool_rule(struct mlx5e_priv * priv,struct mlx5e_ethtool_rule * eth_rule)456 static void del_ethtool_rule(struct mlx5e_priv *priv,
457 			     struct mlx5e_ethtool_rule *eth_rule)
458 {
459 	if (eth_rule->rule)
460 		mlx5_del_flow_rules(eth_rule->rule);
461 	list_del(&eth_rule->list);
462 	priv->fs.ethtool.tot_num_rules--;
463 	put_flow_table(eth_rule->eth_ft);
464 	kfree(eth_rule);
465 }
466 
find_ethtool_rule(struct mlx5e_priv * priv,int location)467 static struct mlx5e_ethtool_rule *find_ethtool_rule(struct mlx5e_priv *priv,
468 						    int location)
469 {
470 	struct mlx5e_ethtool_rule *iter;
471 
472 	list_for_each_entry(iter, &priv->fs.ethtool.rules, list) {
473 		if (iter->flow_spec.location == location)
474 			return iter;
475 	}
476 	return NULL;
477 }
478 
get_ethtool_rule(struct mlx5e_priv * priv,int location)479 static struct mlx5e_ethtool_rule *get_ethtool_rule(struct mlx5e_priv *priv,
480 						   int location)
481 {
482 	struct mlx5e_ethtool_rule *eth_rule;
483 
484 	eth_rule = find_ethtool_rule(priv, location);
485 	if (eth_rule)
486 		del_ethtool_rule(priv, eth_rule);
487 
488 	eth_rule = kzalloc(sizeof(*eth_rule), GFP_KERNEL);
489 	if (!eth_rule)
490 		return ERR_PTR(-ENOMEM);
491 
492 	add_rule_to_list(priv, eth_rule);
493 	return eth_rule;
494 }
495 
496 #define MAX_NUM_OF_ETHTOOL_RULES BIT(10)
497 
498 #define all_ones(field) (field == (__force typeof(field))-1)
499 #define all_zeros_or_all_ones(field)		\
500 	((field) == 0 || (field) == (__force typeof(field))-1)
501 
validate_ethter(struct ethtool_rx_flow_spec * fs)502 static int validate_ethter(struct ethtool_rx_flow_spec *fs)
503 {
504 	struct ethhdr *eth_mask = &fs->m_u.ether_spec;
505 	int ntuples = 0;
506 
507 	if (!is_zero_ether_addr(eth_mask->h_dest))
508 		ntuples++;
509 	if (!is_zero_ether_addr(eth_mask->h_source))
510 		ntuples++;
511 	if (eth_mask->h_proto)
512 		ntuples++;
513 	return ntuples;
514 }
515 
validate_tcpudp4(struct ethtool_rx_flow_spec * fs)516 static int validate_tcpudp4(struct ethtool_rx_flow_spec *fs)
517 {
518 	struct ethtool_tcpip4_spec *l4_mask = &fs->m_u.tcp_ip4_spec;
519 	int ntuples = 0;
520 
521 	if (l4_mask->tos)
522 		return -EINVAL;
523 
524 	if (l4_mask->ip4src)
525 		ntuples++;
526 	if (l4_mask->ip4dst)
527 		ntuples++;
528 	if (l4_mask->psrc)
529 		ntuples++;
530 	if (l4_mask->pdst)
531 		ntuples++;
532 	/* Flow is TCP/UDP */
533 	return ++ntuples;
534 }
535 
validate_ip4(struct ethtool_rx_flow_spec * fs)536 static int validate_ip4(struct ethtool_rx_flow_spec *fs)
537 {
538 	struct ethtool_usrip4_spec *l3_mask = &fs->m_u.usr_ip4_spec;
539 	int ntuples = 0;
540 
541 	if (l3_mask->l4_4_bytes || l3_mask->tos ||
542 	    fs->h_u.usr_ip4_spec.ip_ver != ETH_RX_NFC_IP4)
543 		return -EINVAL;
544 	if (l3_mask->ip4src)
545 		ntuples++;
546 	if (l3_mask->ip4dst)
547 		ntuples++;
548 	if (l3_mask->proto)
549 		ntuples++;
550 	/* Flow is IPv4 */
551 	return ++ntuples;
552 }
553 
validate_ip6(struct ethtool_rx_flow_spec * fs)554 static int validate_ip6(struct ethtool_rx_flow_spec *fs)
555 {
556 	struct ethtool_usrip6_spec *l3_mask = &fs->m_u.usr_ip6_spec;
557 	int ntuples = 0;
558 
559 	if (l3_mask->l4_4_bytes || l3_mask->tclass)
560 		return -EINVAL;
561 	if (!ipv6_addr_any((struct in6_addr *)l3_mask->ip6src))
562 		ntuples++;
563 
564 	if (!ipv6_addr_any((struct in6_addr *)l3_mask->ip6dst))
565 		ntuples++;
566 	if (l3_mask->l4_proto)
567 		ntuples++;
568 	/* Flow is IPv6 */
569 	return ++ntuples;
570 }
571 
validate_tcpudp6(struct ethtool_rx_flow_spec * fs)572 static int validate_tcpudp6(struct ethtool_rx_flow_spec *fs)
573 {
574 	struct ethtool_tcpip6_spec *l4_mask = &fs->m_u.tcp_ip6_spec;
575 	int ntuples = 0;
576 
577 	if (l4_mask->tclass)
578 		return -EINVAL;
579 
580 	if (!ipv6_addr_any((struct in6_addr *)l4_mask->ip6src))
581 		ntuples++;
582 
583 	if (!ipv6_addr_any((struct in6_addr *)l4_mask->ip6dst))
584 		ntuples++;
585 
586 	if (l4_mask->psrc)
587 		ntuples++;
588 	if (l4_mask->pdst)
589 		ntuples++;
590 	/* Flow is TCP/UDP */
591 	return ++ntuples;
592 }
593 
validate_vlan(struct ethtool_rx_flow_spec * fs)594 static int validate_vlan(struct ethtool_rx_flow_spec *fs)
595 {
596 	if (fs->m_ext.vlan_etype ||
597 	    fs->m_ext.vlan_tci != cpu_to_be16(VLAN_VID_MASK))
598 		return -EINVAL;
599 
600 	if (fs->m_ext.vlan_tci &&
601 	    (be16_to_cpu(fs->h_ext.vlan_tci) >= VLAN_N_VID))
602 		return -EINVAL;
603 
604 	return 1;
605 }
606 
validate_flow(struct mlx5e_priv * priv,struct ethtool_rx_flow_spec * fs)607 static int validate_flow(struct mlx5e_priv *priv,
608 			 struct ethtool_rx_flow_spec *fs)
609 {
610 	int num_tuples = 0;
611 	int ret = 0;
612 
613 	if (fs->location >= MAX_NUM_OF_ETHTOOL_RULES)
614 		return -ENOSPC;
615 
616 	if (fs->ring_cookie != RX_CLS_FLOW_DISC)
617 		if (!mlx5e_qid_validate(priv->profile, &priv->channels.params,
618 					fs->ring_cookie))
619 			return -EINVAL;
620 
621 	switch (fs->flow_type & ~(FLOW_EXT | FLOW_MAC_EXT)) {
622 	case ETHER_FLOW:
623 		num_tuples += validate_ethter(fs);
624 		break;
625 	case TCP_V4_FLOW:
626 	case UDP_V4_FLOW:
627 		ret = validate_tcpudp4(fs);
628 		if (ret < 0)
629 			return ret;
630 		num_tuples += ret;
631 		break;
632 	case IP_USER_FLOW:
633 		ret = validate_ip4(fs);
634 		if (ret < 0)
635 			return ret;
636 		num_tuples += ret;
637 		break;
638 	case TCP_V6_FLOW:
639 	case UDP_V6_FLOW:
640 		ret = validate_tcpudp6(fs);
641 		if (ret < 0)
642 			return ret;
643 		num_tuples += ret;
644 		break;
645 	case IPV6_USER_FLOW:
646 		ret = validate_ip6(fs);
647 		if (ret < 0)
648 			return ret;
649 		num_tuples += ret;
650 		break;
651 	default:
652 		return -ENOTSUPP;
653 	}
654 	if ((fs->flow_type & FLOW_EXT)) {
655 		ret = validate_vlan(fs);
656 		if (ret < 0)
657 			return ret;
658 		num_tuples += ret;
659 	}
660 
661 	if (fs->flow_type & FLOW_MAC_EXT &&
662 	    !is_zero_ether_addr(fs->m_ext.h_dest))
663 		num_tuples++;
664 
665 	return num_tuples;
666 }
667 
668 static int
mlx5e_ethtool_flow_replace(struct mlx5e_priv * priv,struct ethtool_rx_flow_spec * fs)669 mlx5e_ethtool_flow_replace(struct mlx5e_priv *priv,
670 			   struct ethtool_rx_flow_spec *fs)
671 {
672 	struct mlx5e_ethtool_table *eth_ft;
673 	struct mlx5e_ethtool_rule *eth_rule;
674 	struct mlx5_flow_handle *rule;
675 	int num_tuples;
676 	int err;
677 
678 	num_tuples = validate_flow(priv, fs);
679 	if (num_tuples <= 0) {
680 		netdev_warn(priv->netdev, "%s: flow is not valid %d\n",
681 			    __func__, num_tuples);
682 		return num_tuples;
683 	}
684 
685 	eth_ft = get_flow_table(priv, fs, num_tuples);
686 	if (IS_ERR(eth_ft))
687 		return PTR_ERR(eth_ft);
688 
689 	eth_rule = get_ethtool_rule(priv, fs->location);
690 	if (IS_ERR(eth_rule)) {
691 		put_flow_table(eth_ft);
692 		return PTR_ERR(eth_rule);
693 	}
694 
695 	eth_rule->flow_spec = *fs;
696 	eth_rule->eth_ft = eth_ft;
697 	if (!eth_ft->ft) {
698 		err = -EINVAL;
699 		goto del_ethtool_rule;
700 	}
701 	rule = add_ethtool_flow_rule(priv, eth_ft->ft, fs);
702 	if (IS_ERR(rule)) {
703 		err = PTR_ERR(rule);
704 		goto del_ethtool_rule;
705 	}
706 
707 	eth_rule->rule = rule;
708 
709 	return 0;
710 
711 del_ethtool_rule:
712 	del_ethtool_rule(priv, eth_rule);
713 
714 	return err;
715 }
716 
717 static int
mlx5e_ethtool_flow_remove(struct mlx5e_priv * priv,int location)718 mlx5e_ethtool_flow_remove(struct mlx5e_priv *priv, int location)
719 {
720 	struct mlx5e_ethtool_rule *eth_rule;
721 	int err = 0;
722 
723 	if (location >= MAX_NUM_OF_ETHTOOL_RULES)
724 		return -ENOSPC;
725 
726 	eth_rule = find_ethtool_rule(priv, location);
727 	if (!eth_rule) {
728 		err =  -ENOENT;
729 		goto out;
730 	}
731 
732 	del_ethtool_rule(priv, eth_rule);
733 out:
734 	return err;
735 }
736 
737 static int
mlx5e_ethtool_get_flow(struct mlx5e_priv * priv,struct ethtool_rxnfc * info,int location)738 mlx5e_ethtool_get_flow(struct mlx5e_priv *priv,
739 		       struct ethtool_rxnfc *info, int location)
740 {
741 	struct mlx5e_ethtool_rule *eth_rule;
742 
743 	if (location < 0 || location >= MAX_NUM_OF_ETHTOOL_RULES)
744 		return -EINVAL;
745 
746 	list_for_each_entry(eth_rule, &priv->fs.ethtool.rules, list) {
747 		if (eth_rule->flow_spec.location == location) {
748 			info->fs = eth_rule->flow_spec;
749 			return 0;
750 		}
751 	}
752 
753 	return -ENOENT;
754 }
755 
756 static int
mlx5e_ethtool_get_all_flows(struct mlx5e_priv * priv,struct ethtool_rxnfc * info,u32 * rule_locs)757 mlx5e_ethtool_get_all_flows(struct mlx5e_priv *priv,
758 			    struct ethtool_rxnfc *info, u32 *rule_locs)
759 {
760 	int location = 0;
761 	int idx = 0;
762 	int err = 0;
763 
764 	info->data = MAX_NUM_OF_ETHTOOL_RULES;
765 	while ((!err || err == -ENOENT) && idx < info->rule_cnt) {
766 		err = mlx5e_ethtool_get_flow(priv, info, location);
767 		if (!err)
768 			rule_locs[idx++] = location;
769 		location++;
770 	}
771 	return err;
772 }
773 
mlx5e_ethtool_cleanup_steering(struct mlx5e_priv * priv)774 void mlx5e_ethtool_cleanup_steering(struct mlx5e_priv *priv)
775 {
776 	struct mlx5e_ethtool_rule *iter;
777 	struct mlx5e_ethtool_rule *temp;
778 
779 	list_for_each_entry_safe(iter, temp, &priv->fs.ethtool.rules, list)
780 		del_ethtool_rule(priv, iter);
781 }
782 
mlx5e_ethtool_init_steering(struct mlx5e_priv * priv)783 void mlx5e_ethtool_init_steering(struct mlx5e_priv *priv)
784 {
785 	INIT_LIST_HEAD(&priv->fs.ethtool.rules);
786 }
787 
flow_type_to_traffic_type(u32 flow_type)788 static enum mlx5e_traffic_types flow_type_to_traffic_type(u32 flow_type)
789 {
790 	switch (flow_type) {
791 	case TCP_V4_FLOW:
792 		return  MLX5E_TT_IPV4_TCP;
793 	case TCP_V6_FLOW:
794 		return MLX5E_TT_IPV6_TCP;
795 	case UDP_V4_FLOW:
796 		return MLX5E_TT_IPV4_UDP;
797 	case UDP_V6_FLOW:
798 		return MLX5E_TT_IPV6_UDP;
799 	case AH_V4_FLOW:
800 		return MLX5E_TT_IPV4_IPSEC_AH;
801 	case AH_V6_FLOW:
802 		return MLX5E_TT_IPV6_IPSEC_AH;
803 	case ESP_V4_FLOW:
804 		return MLX5E_TT_IPV4_IPSEC_ESP;
805 	case ESP_V6_FLOW:
806 		return MLX5E_TT_IPV6_IPSEC_ESP;
807 	case IPV4_FLOW:
808 		return MLX5E_TT_IPV4;
809 	case IPV6_FLOW:
810 		return MLX5E_TT_IPV6;
811 	default:
812 		return MLX5E_NUM_INDIR_TIRS;
813 	}
814 }
815 
mlx5e_set_rss_hash_opt(struct mlx5e_priv * priv,struct ethtool_rxnfc * nfc)816 static int mlx5e_set_rss_hash_opt(struct mlx5e_priv *priv,
817 				  struct ethtool_rxnfc *nfc)
818 {
819 	int inlen = MLX5_ST_SZ_BYTES(modify_tir_in);
820 	enum mlx5e_traffic_types tt;
821 	u8 rx_hash_field = 0;
822 	void *in;
823 
824 	tt = flow_type_to_traffic_type(nfc->flow_type);
825 	if (tt == MLX5E_NUM_INDIR_TIRS)
826 		return -EINVAL;
827 
828 	/*  RSS does not support anything other than hashing to queues
829 	 *  on src IP, dest IP, TCP/UDP src port and TCP/UDP dest
830 	 *  port.
831 	 */
832 	if (nfc->flow_type != TCP_V4_FLOW &&
833 	    nfc->flow_type != TCP_V6_FLOW &&
834 	    nfc->flow_type != UDP_V4_FLOW &&
835 	    nfc->flow_type != UDP_V6_FLOW)
836 		return -EOPNOTSUPP;
837 
838 	if (nfc->data & ~(RXH_IP_SRC | RXH_IP_DST |
839 			  RXH_L4_B_0_1 | RXH_L4_B_2_3))
840 		return -EOPNOTSUPP;
841 
842 	if (nfc->data & RXH_IP_SRC)
843 		rx_hash_field |= MLX5_HASH_FIELD_SEL_SRC_IP;
844 	if (nfc->data & RXH_IP_DST)
845 		rx_hash_field |= MLX5_HASH_FIELD_SEL_DST_IP;
846 	if (nfc->data & RXH_L4_B_0_1)
847 		rx_hash_field |= MLX5_HASH_FIELD_SEL_L4_SPORT;
848 	if (nfc->data & RXH_L4_B_2_3)
849 		rx_hash_field |= MLX5_HASH_FIELD_SEL_L4_DPORT;
850 
851 	in = kvzalloc(inlen, GFP_KERNEL);
852 	if (!in)
853 		return -ENOMEM;
854 
855 	mutex_lock(&priv->state_lock);
856 
857 	if (rx_hash_field == priv->rss_params.rx_hash_fields[tt])
858 		goto out;
859 
860 	priv->rss_params.rx_hash_fields[tt] = rx_hash_field;
861 	mlx5e_modify_tirs_hash(priv, in);
862 
863 out:
864 	mutex_unlock(&priv->state_lock);
865 	kvfree(in);
866 	return 0;
867 }
868 
mlx5e_get_rss_hash_opt(struct mlx5e_priv * priv,struct ethtool_rxnfc * nfc)869 static int mlx5e_get_rss_hash_opt(struct mlx5e_priv *priv,
870 				  struct ethtool_rxnfc *nfc)
871 {
872 	enum mlx5e_traffic_types tt;
873 	u32 hash_field = 0;
874 
875 	tt = flow_type_to_traffic_type(nfc->flow_type);
876 	if (tt == MLX5E_NUM_INDIR_TIRS)
877 		return -EINVAL;
878 
879 	hash_field = priv->rss_params.rx_hash_fields[tt];
880 	nfc->data = 0;
881 
882 	if (hash_field & MLX5_HASH_FIELD_SEL_SRC_IP)
883 		nfc->data |= RXH_IP_SRC;
884 	if (hash_field & MLX5_HASH_FIELD_SEL_DST_IP)
885 		nfc->data |= RXH_IP_DST;
886 	if (hash_field & MLX5_HASH_FIELD_SEL_L4_SPORT)
887 		nfc->data |= RXH_L4_B_0_1;
888 	if (hash_field & MLX5_HASH_FIELD_SEL_L4_DPORT)
889 		nfc->data |= RXH_L4_B_2_3;
890 
891 	return 0;
892 }
893 
mlx5e_ethtool_set_rxnfc(struct net_device * dev,struct ethtool_rxnfc * cmd)894 int mlx5e_ethtool_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd)
895 {
896 	struct mlx5e_priv *priv = netdev_priv(dev);
897 	int err = 0;
898 
899 	switch (cmd->cmd) {
900 	case ETHTOOL_SRXCLSRLINS:
901 		err = mlx5e_ethtool_flow_replace(priv, &cmd->fs);
902 		break;
903 	case ETHTOOL_SRXCLSRLDEL:
904 		err = mlx5e_ethtool_flow_remove(priv, cmd->fs.location);
905 		break;
906 	case ETHTOOL_SRXFH:
907 		err = mlx5e_set_rss_hash_opt(priv, cmd);
908 		break;
909 	default:
910 		err = -EOPNOTSUPP;
911 		break;
912 	}
913 
914 	return err;
915 }
916 
mlx5e_ethtool_get_rxnfc(struct net_device * dev,struct ethtool_rxnfc * info,u32 * rule_locs)917 int mlx5e_ethtool_get_rxnfc(struct net_device *dev,
918 			    struct ethtool_rxnfc *info, u32 *rule_locs)
919 {
920 	struct mlx5e_priv *priv = netdev_priv(dev);
921 	int err = 0;
922 
923 	switch (info->cmd) {
924 	case ETHTOOL_GRXCLSRLCNT:
925 		info->rule_cnt = priv->fs.ethtool.tot_num_rules;
926 		break;
927 	case ETHTOOL_GRXCLSRULE:
928 		err = mlx5e_ethtool_get_flow(priv, info, info->fs.location);
929 		break;
930 	case ETHTOOL_GRXCLSRLALL:
931 		err = mlx5e_ethtool_get_all_flows(priv, info, rule_locs);
932 		break;
933 	case ETHTOOL_GRXFH:
934 		err =  mlx5e_get_rss_hash_opt(priv, info);
935 		break;
936 	default:
937 		err = -EOPNOTSUPP;
938 		break;
939 	}
940 
941 	return err;
942 }
943 
944