1/*
2 * Copyright (c) 2017, 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#define CREATE_TRACE_POINTS
34
35#include "fs_tracepoint.h"
36#include <linux/stringify.h>
37
38#define DECLARE_MASK_VAL(type, name) struct {type m; type v; } name
39#define MASK_VAL(type, spec, name, mask, val, fld)	\
40		DECLARE_MASK_VAL(type, name) =		\
41			{.m = MLX5_GET(spec, mask, fld),\
42			 .v = MLX5_GET(spec, val, fld)}
43#define MASK_VAL_BE(type, spec, name, mask, val, fld)	\
44		    DECLARE_MASK_VAL(type, name) =	\
45			{.m = MLX5_GET_BE(type, spec, mask, fld),\
46			 .v = MLX5_GET_BE(type, spec, val, fld)}
47#define GET_MASKED_VAL(name) (name.m & name.v)
48
49#define GET_MASK_VAL(name, type, mask, val, fld)	\
50		(name.m = MLX5_GET(type, mask, fld),	\
51		 name.v = MLX5_GET(type, val, fld),	\
52		 name.m & name.v)
53#define PRINT_MASKED_VAL(name, p, format) {		\
54	if (name.m)			\
55		trace_seq_printf(p, __stringify(name) "=" format " ", name.v); \
56	}
57#define PRINT_MASKED_VALP(name, cast, p, format) {	\
58	if (name.m)			\
59		trace_seq_printf(p, __stringify(name) "=" format " ",	       \
60				 (cast)&name.v);\
61	}
62
63static void print_lyr_2_4_hdrs(struct trace_seq *p,
64			       const u32 *mask, const u32 *value)
65{
66#define MASK_VAL_L2(type, name, fld) \
67	MASK_VAL(type, fte_match_set_lyr_2_4, name, mask, value, fld)
68	DECLARE_MASK_VAL(u64, smac) = {
69		.m = MLX5_GET(fte_match_set_lyr_2_4, mask, smac_47_16) << 16 |
70		     MLX5_GET(fte_match_set_lyr_2_4, mask, smac_15_0),
71		.v = MLX5_GET(fte_match_set_lyr_2_4, value, smac_47_16) << 16 |
72		     MLX5_GET(fte_match_set_lyr_2_4, value, smac_15_0)};
73	DECLARE_MASK_VAL(u64, dmac) = {
74		.m = MLX5_GET(fte_match_set_lyr_2_4, mask, dmac_47_16) << 16 |
75		     MLX5_GET(fte_match_set_lyr_2_4, mask, dmac_15_0),
76		.v = MLX5_GET(fte_match_set_lyr_2_4, value, dmac_47_16) << 16 |
77		     MLX5_GET(fte_match_set_lyr_2_4, value, dmac_15_0)};
78	MASK_VAL_L2(u16, ethertype, ethertype);
79	MASK_VAL_L2(u8, ip_version, ip_version);
80
81	PRINT_MASKED_VALP(smac, u8 *, p, "%pM");
82	PRINT_MASKED_VALP(dmac, u8 *, p, "%pM");
83	PRINT_MASKED_VAL(ethertype, p, "%04x");
84
85	if ((ethertype.m == 0xffff && ethertype.v == ETH_P_IP) ||
86	    (ip_version.m == 0xf && ip_version.v == 4)) {
87#define MASK_VAL_L2_BE(type, name, fld) \
88	MASK_VAL_BE(type, fte_match_set_lyr_2_4, name, mask, value, fld)
89		MASK_VAL_L2_BE(u32, src_ipv4,
90			       src_ipv4_src_ipv6.ipv4_layout.ipv4);
91		MASK_VAL_L2_BE(u32, dst_ipv4,
92			       dst_ipv4_dst_ipv6.ipv4_layout.ipv4);
93
94		PRINT_MASKED_VALP(src_ipv4, typeof(&src_ipv4.v), p,
95				  "%pI4");
96		PRINT_MASKED_VALP(dst_ipv4, typeof(&dst_ipv4.v), p,
97				  "%pI4");
98	} else if ((ethertype.m == 0xffff && ethertype.v == ETH_P_IPV6) ||
99		   (ip_version.m == 0xf && ip_version.v == 6)) {
100		static const struct in6_addr full_ones = {
101			.in6_u.u6_addr32 = {__constant_htonl(0xffffffff),
102					    __constant_htonl(0xffffffff),
103					    __constant_htonl(0xffffffff),
104					    __constant_htonl(0xffffffff)},
105		};
106		DECLARE_MASK_VAL(struct in6_addr, src_ipv6);
107		DECLARE_MASK_VAL(struct in6_addr, dst_ipv6);
108
109		memcpy(src_ipv6.m.in6_u.u6_addr8,
110		       MLX5_ADDR_OF(fte_match_set_lyr_2_4, mask,
111				    src_ipv4_src_ipv6.ipv6_layout.ipv6),
112		       sizeof(src_ipv6.m));
113		memcpy(dst_ipv6.m.in6_u.u6_addr8,
114		       MLX5_ADDR_OF(fte_match_set_lyr_2_4, mask,
115				    dst_ipv4_dst_ipv6.ipv6_layout.ipv6),
116		       sizeof(dst_ipv6.m));
117		memcpy(src_ipv6.v.in6_u.u6_addr8,
118		       MLX5_ADDR_OF(fte_match_set_lyr_2_4, value,
119				    src_ipv4_src_ipv6.ipv6_layout.ipv6),
120		       sizeof(src_ipv6.v));
121		memcpy(dst_ipv6.v.in6_u.u6_addr8,
122		       MLX5_ADDR_OF(fte_match_set_lyr_2_4, value,
123				    dst_ipv4_dst_ipv6.ipv6_layout.ipv6),
124		       sizeof(dst_ipv6.v));
125
126		if (!memcmp(&src_ipv6.m, &full_ones, sizeof(full_ones)))
127			trace_seq_printf(p, "src_ipv6=%pI6 ",
128					 &src_ipv6.v);
129		if (!memcmp(&dst_ipv6.m, &full_ones, sizeof(full_ones)))
130			trace_seq_printf(p, "dst_ipv6=%pI6 ",
131					 &dst_ipv6.v);
132	}
133
134#define PRINT_MASKED_VAL_L2(type, name, fld, p, format) {\
135	MASK_VAL_L2(type, name, fld);		         \
136	PRINT_MASKED_VAL(name, p, format);		 \
137}
138
139	PRINT_MASKED_VAL_L2(u8, ip_protocol, ip_protocol, p, "%02x");
140	PRINT_MASKED_VAL_L2(u16, tcp_flags, tcp_flags, p, "%x");
141	PRINT_MASKED_VAL_L2(u16, tcp_sport, tcp_sport, p, "%u");
142	PRINT_MASKED_VAL_L2(u16, tcp_dport, tcp_dport, p, "%u");
143	PRINT_MASKED_VAL_L2(u16, udp_sport, udp_sport, p, "%u");
144	PRINT_MASKED_VAL_L2(u16, udp_dport, udp_dport, p, "%u");
145	PRINT_MASKED_VAL_L2(u16, first_vid, first_vid, p, "%04x");
146	PRINT_MASKED_VAL_L2(u8, first_prio, first_prio, p, "%x");
147	PRINT_MASKED_VAL_L2(u8, first_cfi, first_cfi, p, "%d");
148	PRINT_MASKED_VAL_L2(u8, ip_dscp, ip_dscp, p, "%02x");
149	PRINT_MASKED_VAL_L2(u8, ip_ecn, ip_ecn, p, "%x");
150	PRINT_MASKED_VAL_L2(u8, cvlan_tag, cvlan_tag, p, "%d");
151	PRINT_MASKED_VAL_L2(u8, svlan_tag, svlan_tag, p, "%d");
152	PRINT_MASKED_VAL_L2(u8, frag, frag, p, "%d");
153}
154
155static void print_misc_parameters_hdrs(struct trace_seq *p,
156				       const u32 *mask, const u32 *value)
157{
158#define MASK_VAL_MISC(type, name, fld) \
159	MASK_VAL(type, fte_match_set_misc, name, mask, value, fld)
160#define PRINT_MASKED_VAL_MISC(type, name, fld, p, format) {\
161	MASK_VAL_MISC(type, name, fld);			   \
162	PRINT_MASKED_VAL(name, p, format);		   \
163}
164	DECLARE_MASK_VAL(u64, gre_key) = {
165		.m = MLX5_GET(fte_match_set_misc, mask, gre_key.nvgre.hi) << 8 |
166		     MLX5_GET(fte_match_set_misc, mask, gre_key.nvgre.lo),
167		.v = MLX5_GET(fte_match_set_misc, value, gre_key.nvgre.hi) << 8 |
168		     MLX5_GET(fte_match_set_misc, value, gre_key.nvgre.lo)};
169
170	PRINT_MASKED_VAL(gre_key, p, "%llu");
171	PRINT_MASKED_VAL_MISC(u32, source_sqn, source_sqn, p, "%u");
172	PRINT_MASKED_VAL_MISC(u16, source_port, source_port, p, "%u");
173	PRINT_MASKED_VAL_MISC(u8, outer_second_prio, outer_second_prio,
174			      p, "%u");
175	PRINT_MASKED_VAL_MISC(u8, outer_second_cfi, outer_second_cfi, p, "%u");
176	PRINT_MASKED_VAL_MISC(u16, outer_second_vid, outer_second_vid, p, "%u");
177	PRINT_MASKED_VAL_MISC(u8, inner_second_prio, inner_second_prio,
178			      p, "%u");
179	PRINT_MASKED_VAL_MISC(u8, inner_second_cfi, inner_second_cfi, p, "%u");
180	PRINT_MASKED_VAL_MISC(u16, inner_second_vid, inner_second_vid, p, "%u");
181
182	PRINT_MASKED_VAL_MISC(u8, outer_second_cvlan_tag,
183			      outer_second_cvlan_tag, p, "%u");
184	PRINT_MASKED_VAL_MISC(u8, inner_second_cvlan_tag,
185			      inner_second_cvlan_tag, p, "%u");
186	PRINT_MASKED_VAL_MISC(u8, outer_second_svlan_tag,
187			      outer_second_svlan_tag, p, "%u");
188	PRINT_MASKED_VAL_MISC(u8, inner_second_svlan_tag,
189			      inner_second_svlan_tag, p, "%u");
190
191	PRINT_MASKED_VAL_MISC(u8, gre_protocol, gre_protocol, p, "%u");
192
193	PRINT_MASKED_VAL_MISC(u32, vxlan_vni, vxlan_vni, p, "%u");
194	PRINT_MASKED_VAL_MISC(u32, outer_ipv6_flow_label, outer_ipv6_flow_label,
195			      p, "%x");
196	PRINT_MASKED_VAL_MISC(u32, inner_ipv6_flow_label, inner_ipv6_flow_label,
197			      p, "%x");
198}
199
200const char *parse_fs_hdrs(struct trace_seq *p,
201			  u8 match_criteria_enable,
202			  const u32 *mask_outer,
203			  const u32 *mask_misc,
204			  const u32 *mask_inner,
205			  const u32 *value_outer,
206			  const u32 *value_misc,
207			  const u32 *value_inner)
208{
209	const char *ret = trace_seq_buffer_ptr(p);
210
211	if (match_criteria_enable &
212	    1 << MLX5_CREATE_FLOW_GROUP_IN_MATCH_CRITERIA_ENABLE_OUTER_HEADERS) {
213		trace_seq_printf(p, "[outer] ");
214		print_lyr_2_4_hdrs(p, mask_outer, value_outer);
215	}
216
217	if (match_criteria_enable &
218	    1 << MLX5_CREATE_FLOW_GROUP_IN_MATCH_CRITERIA_ENABLE_MISC_PARAMETERS) {
219		trace_seq_printf(p, "[misc] ");
220		print_misc_parameters_hdrs(p, mask_misc, value_misc);
221	}
222	if (match_criteria_enable &
223	    1 << MLX5_CREATE_FLOW_GROUP_IN_MATCH_CRITERIA_ENABLE_INNER_HEADERS) {
224		trace_seq_printf(p, "[inner] ");
225		print_lyr_2_4_hdrs(p, mask_inner, value_inner);
226	}
227	trace_seq_putc(p, 0);
228	return ret;
229}
230
231static const char
232*fs_dest_range_field_to_str(enum mlx5_flow_dest_range_field field)
233{
234	switch (field) {
235	case MLX5_FLOW_DEST_RANGE_FIELD_PKT_LEN:
236		return "packet len";
237	default:
238		return "unknown dest range field";
239	}
240}
241
242const char *parse_fs_dst(struct trace_seq *p,
243			 const struct mlx5_flow_destination *dst,
244			 u32 counter_id)
245{
246	const char *ret = trace_seq_buffer_ptr(p);
247
248	switch (dst->type) {
249	case MLX5_FLOW_DESTINATION_TYPE_UPLINK:
250		trace_seq_printf(p, "uplink\n");
251		break;
252	case MLX5_FLOW_DESTINATION_TYPE_VPORT:
253		trace_seq_printf(p, "vport=%u\n", dst->vport.num);
254		break;
255	case MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE:
256		trace_seq_printf(p, "ft=%p\n", dst->ft);
257		break;
258	case MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE_NUM:
259		trace_seq_printf(p, "ft_num=%u\n", dst->ft_num);
260		break;
261	case MLX5_FLOW_DESTINATION_TYPE_TIR:
262		trace_seq_printf(p, "tir=%u\n", dst->tir_num);
263		break;
264	case MLX5_FLOW_DESTINATION_TYPE_FLOW_SAMPLER:
265		trace_seq_printf(p, "sampler_id=%u\n", dst->sampler_id);
266		break;
267	case MLX5_FLOW_DESTINATION_TYPE_COUNTER:
268		trace_seq_printf(p, "counter_id=%u\n", counter_id);
269		break;
270	case MLX5_FLOW_DESTINATION_TYPE_PORT:
271		trace_seq_printf(p, "port\n");
272		break;
273	case MLX5_FLOW_DESTINATION_TYPE_RANGE:
274		trace_seq_printf(p, "field=%s min=%d max=%d\n",
275				 fs_dest_range_field_to_str(dst->range.field),
276				 dst->range.min, dst->range.max);
277		break;
278	case MLX5_FLOW_DESTINATION_TYPE_TABLE_TYPE:
279		trace_seq_printf(p, "flow_table_type=%u id:%u\n", dst->ft->type,
280				 dst->ft->id);
281		break;
282	case MLX5_FLOW_DESTINATION_TYPE_NONE:
283		trace_seq_printf(p, "none\n");
284		break;
285	}
286
287	trace_seq_putc(p, 0);
288	return ret;
289}
290
291EXPORT_TRACEPOINT_SYMBOL(mlx5_fs_add_ft);
292EXPORT_TRACEPOINT_SYMBOL(mlx5_fs_del_ft);
293EXPORT_TRACEPOINT_SYMBOL(mlx5_fs_add_fg);
294EXPORT_TRACEPOINT_SYMBOL(mlx5_fs_del_fg);
295EXPORT_TRACEPOINT_SYMBOL(mlx5_fs_set_fte);
296EXPORT_TRACEPOINT_SYMBOL(mlx5_fs_del_fte);
297EXPORT_TRACEPOINT_SYMBOL(mlx5_fs_add_rule);
298EXPORT_TRACEPOINT_SYMBOL(mlx5_fs_del_rule);
299
300