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