• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2016 Fabien Siron <fabien.siron@epita.fr>
3  * Copyright (c) 2017 JingPiao Chen <chenjingpiao@gmail.com>
4  * Copyright (c) 2016-2018 The strace developers.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. The name of the author may not be used to endorse or promote products
16  *    derived from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 #include "defs.h"
31 #include "netlink_route.h"
32 #include "nlattr.h"
33 #include "print_fields.h"
34 
35 #include "netlink.h"
36 #ifdef HAVE_STRUCT_GNET_STATS_BASIC
37 # include <linux/gen_stats.h>
38 #endif
39 #include <linux/pkt_sched.h>
40 #include <linux/rtnetlink.h>
41 
42 #include "xlat/rtnl_tc_attrs.h"
43 #include "xlat/rtnl_tca_stab_attrs.h"
44 #include "xlat/rtnl_tca_stats_attrs.h"
45 
46 static bool
decode_tc_stats(struct tcb * const tcp,const kernel_ulong_t addr,const unsigned int len,const void * const opaque_data)47 decode_tc_stats(struct tcb *const tcp,
48 		const kernel_ulong_t addr,
49 		const unsigned int len,
50 		const void *const opaque_data)
51 {
52 	struct tc_stats st;
53 	const unsigned int sizeof_tc_stats =
54 		offsetofend(struct tc_stats, backlog);
55 
56 	if (len < sizeof_tc_stats)
57 		return false;
58 	else if (!umoven_or_printaddr(tcp, addr, sizeof_tc_stats, &st)) {
59 		PRINT_FIELD_U("{", st, bytes);
60 		PRINT_FIELD_U(", ", st, packets);
61 		PRINT_FIELD_U(", ", st, drops);
62 		PRINT_FIELD_U(", ", st, overlimits);
63 		PRINT_FIELD_U(", ", st, bps);
64 		PRINT_FIELD_U(", ", st, pps);
65 		PRINT_FIELD_U(", ", st, qlen);
66 		PRINT_FIELD_U(", ", st, backlog);
67 		tprints("}");
68 	}
69 
70 	return true;
71 }
72 
73 static bool
decode_tc_estimator(struct tcb * const tcp,const kernel_ulong_t addr,const unsigned int len,const void * const opaque_data)74 decode_tc_estimator(struct tcb *const tcp,
75 		    const kernel_ulong_t addr,
76 		    const unsigned int len,
77 		    const void *const opaque_data)
78 {
79 	struct tc_estimator est;
80 
81 	if (len < sizeof(est))
82 		return false;
83 	else if (!umove_or_printaddr(tcp, addr, &est)) {
84 		PRINT_FIELD_D("{", est, interval);
85 		PRINT_FIELD_U(", ", est, ewma_log);
86 		tprints("}");
87 	}
88 
89 	return true;
90 }
91 
92 static bool
decode_gnet_stats_basic(struct tcb * const tcp,const kernel_ulong_t addr,const unsigned int len,const void * const opaque_data)93 decode_gnet_stats_basic(struct tcb *const tcp,
94 			const kernel_ulong_t addr,
95 			const unsigned int len,
96 			const void *const opaque_data)
97 {
98 #ifdef HAVE_STRUCT_GNET_STATS_BASIC
99 	struct gnet_stats_basic sb;
100 	const unsigned int sizeof_st_basic =
101 		offsetofend(struct gnet_stats_basic, packets);
102 
103 	if (len < sizeof_st_basic)
104 		return false;
105 	else if (!umoven_or_printaddr(tcp, addr, sizeof_st_basic, &sb)) {
106 		PRINT_FIELD_U("{", sb, bytes);
107 		PRINT_FIELD_U(", ", sb, packets);
108 		tprints("}");
109 	}
110 
111 	return true;
112 #else
113 	return false;
114 #endif
115 }
116 
117 static bool
decode_gnet_stats_rate_est(struct tcb * const tcp,const kernel_ulong_t addr,const unsigned int len,const void * const opaque_data)118 decode_gnet_stats_rate_est(struct tcb *const tcp,
119 			   const kernel_ulong_t addr,
120 			   const unsigned int len,
121 			   const void *const opaque_data)
122 {
123 #ifdef HAVE_STRUCT_GNET_STATS_RATE_EST
124 	struct gnet_stats_rate_est est;
125 
126 	if (len < sizeof(est))
127 		return false;
128 	else if (!umove_or_printaddr(tcp, addr, &est)) {
129 		PRINT_FIELD_U("{", est, bps);
130 		PRINT_FIELD_U(", ", est, pps);
131 		tprints("}");
132 	}
133 
134 	return true;
135 #else
136 	return false;
137 #endif
138 }
139 
140 static bool
decode_gnet_stats_queue(struct tcb * const tcp,const kernel_ulong_t addr,const unsigned int len,const void * const opaque_data)141 decode_gnet_stats_queue(struct tcb *const tcp,
142 			const kernel_ulong_t addr,
143 			const unsigned int len,
144 			const void *const opaque_data)
145 {
146 #ifdef HAVE_STRUCT_GNET_STATS_QUEUE
147 	struct gnet_stats_queue qstats;
148 
149 	if (len < sizeof(qstats))
150 		return false;
151 	else if (!umove_or_printaddr(tcp, addr, &qstats)) {
152 		PRINT_FIELD_U("{", qstats, qlen);
153 		PRINT_FIELD_U(", ", qstats, backlog);
154 		PRINT_FIELD_U(", ", qstats, drops);
155 		PRINT_FIELD_U(", ", qstats, requeues);
156 		PRINT_FIELD_U(", ", qstats, overlimits);
157 		tprints("}");
158 	}
159 
160 	return true;
161 #else
162 	return false;
163 #endif
164 }
165 
166 static bool
decode_gnet_stats_rate_est64(struct tcb * const tcp,const kernel_ulong_t addr,const unsigned int len,const void * const opaque_data)167 decode_gnet_stats_rate_est64(struct tcb *const tcp,
168 			     const kernel_ulong_t addr,
169 			     const unsigned int len,
170 			     const void *const opaque_data)
171 {
172 #ifdef HAVE_STRUCT_GNET_STATS_RATE_EST64
173 	struct gnet_stats_rate_est64 est;
174 
175 	if (len < sizeof(est))
176 		return false;
177 	else if (!umove_or_printaddr(tcp, addr, &est)) {
178 		PRINT_FIELD_U("{", est, bps);
179 		PRINT_FIELD_U(", ", est, pps);
180 		tprints("}");
181 	}
182 
183 	return true;
184 #else
185 	return false;
186 #endif
187 }
188 
189 static const nla_decoder_t tca_stats_nla_decoders[] = {
190 	[TCA_STATS_BASIC]	= decode_gnet_stats_basic,
191 	[TCA_STATS_RATE_EST]	= decode_gnet_stats_rate_est,
192 	[TCA_STATS_QUEUE]	= decode_gnet_stats_queue,
193 	[TCA_STATS_APP]		= NULL, /* unimplemented */
194 	[TCA_STATS_RATE_EST64]	= decode_gnet_stats_rate_est64,
195 	[TCA_STATS_PAD]		= NULL,
196 };
197 
198 bool
decode_nla_tc_stats(struct tcb * const tcp,const kernel_ulong_t addr,const unsigned int len,const void * const opaque_data)199 decode_nla_tc_stats(struct tcb *const tcp,
200 		    const kernel_ulong_t addr,
201 		    const unsigned int len,
202 		    const void *const opaque_data)
203 {
204 	decode_nlattr(tcp, addr, len, rtnl_tca_stats_attrs, "TCA_STATS_???",
205 		      tca_stats_nla_decoders,
206 		      ARRAY_SIZE(tca_stats_nla_decoders), opaque_data);
207 
208 	return true;
209 }
210 
211 static bool
decode_tc_sizespec(struct tcb * const tcp,const kernel_ulong_t addr,const unsigned int len,const void * const opaque_data)212 decode_tc_sizespec(struct tcb *const tcp,
213 		   const kernel_ulong_t addr,
214 		   const unsigned int len,
215 		   const void *const opaque_data)
216 {
217 #ifdef HAVE_STRUCT_TC_SIZESPEC
218 	struct tc_sizespec s;
219 
220 	if (len < sizeof(s))
221 		return false;
222 	else if (!umove_or_printaddr(tcp, addr, &s)) {
223 		PRINT_FIELD_U("{", s, cell_log);
224 		PRINT_FIELD_U(", ", s, size_log);
225 		PRINT_FIELD_D(", ", s, cell_align);
226 		PRINT_FIELD_D(", ", s, overhead);
227 		PRINT_FIELD_U(", ", s, linklayer);
228 		PRINT_FIELD_U(", ", s, mpu);
229 		PRINT_FIELD_U(", ", s, mtu);
230 		PRINT_FIELD_U(", ", s, tsize);
231 		tprints("}");
232 	}
233 
234 	return true;
235 #else
236 	return false;
237 #endif
238 }
239 
240 static bool
print_stab_data(struct tcb * const tcp,void * const elem_buf,const size_t elem_size,void * const opaque_data)241 print_stab_data(struct tcb *const tcp, void *const elem_buf,
242 		const size_t elem_size, void *const opaque_data)
243 {
244 	tprintf("%" PRIu16, *(uint16_t *) elem_buf);
245 
246 	return true;
247 }
248 
249 static bool
decode_tca_stab_data(struct tcb * const tcp,const kernel_ulong_t addr,const unsigned int len,const void * const opaque_data)250 decode_tca_stab_data(struct tcb *const tcp,
251 		     const kernel_ulong_t addr,
252 		     const unsigned int len,
253 		     const void *const opaque_data)
254 {
255 	uint16_t data;
256 	const size_t nmemb = len / sizeof(data);
257 
258 	if (!nmemb)
259 		return false;
260 
261 	print_array(tcp, addr, nmemb, &data, sizeof(data),
262 		    tfetch_mem, print_stab_data, NULL);
263 
264 	return true;
265 }
266 
267 static const nla_decoder_t tca_stab_nla_decoders[] = {
268 	[TCA_STAB_BASE]	= decode_tc_sizespec,
269 	[TCA_STAB_DATA] = decode_tca_stab_data
270 };
271 
272 static bool
decode_tca_stab(struct tcb * const tcp,const kernel_ulong_t addr,const unsigned int len,const void * const opaque_data)273 decode_tca_stab(struct tcb *const tcp,
274 		const kernel_ulong_t addr,
275 		const unsigned int len,
276 		const void *const opaque_data)
277 {
278 	decode_nlattr(tcp, addr, len, rtnl_tca_stab_attrs, "TCA_STAB_???",
279 		      tca_stab_nla_decoders,
280 		      ARRAY_SIZE(tca_stab_nla_decoders), opaque_data);
281 
282 	return true;
283 }
284 
285 static const nla_decoder_t tcmsg_nla_decoders[] = {
286 	[TCA_KIND]		= decode_nla_str,
287 	[TCA_OPTIONS]		= NULL, /* unimplemented */
288 	[TCA_STATS]		= decode_tc_stats,
289 	[TCA_XSTATS]		= NULL, /* unimplemented */
290 	[TCA_RATE]		= decode_tc_estimator,
291 	[TCA_FCNT]		= decode_nla_u32,
292 	[TCA_STATS2]		= decode_nla_tc_stats,
293 	[TCA_STAB]		= decode_tca_stab,
294 	[TCA_PAD]		= NULL,
295 	[TCA_DUMP_INVISIBLE]	= NULL,
296 	[TCA_CHAIN]		= decode_nla_u32,
297 	[TCA_HW_OFFLOAD]	= decode_nla_u8,
298 	[TCA_INGRESS_BLOCK]	= decode_nla_u32,
299 	[TCA_EGRESS_BLOCK]	= decode_nla_u32,
300 };
301 
DECL_NETLINK_ROUTE_DECODER(decode_tcmsg)302 DECL_NETLINK_ROUTE_DECODER(decode_tcmsg)
303 {
304 	struct tcmsg tcmsg = { .tcm_family = family };
305 	size_t offset = sizeof(tcmsg.tcm_family);
306 	bool decode_nla = false;
307 
308 	PRINT_FIELD_XVAL("{", tcmsg, tcm_family, addrfams, "AF_???");
309 
310 	tprints(", ");
311 	if (len >= sizeof(tcmsg)) {
312 		if (!umoven_or_printaddr(tcp, addr + offset,
313 					 sizeof(tcmsg) - offset,
314 					 (char *) &tcmsg + offset)) {
315 			PRINT_FIELD_IFINDEX("", tcmsg, tcm_ifindex);
316 			PRINT_FIELD_U(", ", tcmsg, tcm_handle);
317 			PRINT_FIELD_U(", ", tcmsg, tcm_parent);
318 			PRINT_FIELD_U(", ", tcmsg, tcm_info);
319 			decode_nla = true;
320 		}
321 	} else
322 		tprints("...");
323 	tprints("}");
324 
325 	offset = NLMSG_ALIGN(sizeof(tcmsg));
326 	if (decode_nla && len > offset) {
327 		tprints(", ");
328 		decode_nlattr(tcp, addr + offset, len - offset,
329 			      rtnl_tc_attrs, "TCA_???", tcmsg_nla_decoders,
330 			      ARRAY_SIZE(tcmsg_nla_decoders), NULL);
331 	}
332 }
333