]> granicus.if.org Git - strace/blob - rtnl_tc.c
tests: workaround systemd-nspawn habit of disabling unimplemented syscalls
[strace] / rtnl_tc.c
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  * SPDX-License-Identifier: LGPL-2.1-or-later
8  */
9
10 #include "defs.h"
11 #include "netlink_route.h"
12 #include "nlattr.h"
13 #include "print_fields.h"
14
15 #include "netlink.h"
16 #ifdef HAVE_STRUCT_GNET_STATS_BASIC
17 # include <linux/gen_stats.h>
18 #endif
19 #include <linux/pkt_sched.h>
20 #include <linux/rtnetlink.h>
21
22 #include "xlat/rtnl_tc_attrs.h"
23 #include "xlat/rtnl_tca_stab_attrs.h"
24 #include "xlat/rtnl_tca_stats_attrs.h"
25
26 static bool
27 decode_tc_stats(struct tcb *const tcp,
28                 const kernel_ulong_t addr,
29                 const unsigned int len,
30                 const void *const opaque_data)
31 {
32         struct tc_stats st;
33         const unsigned int sizeof_tc_stats =
34                 offsetofend(struct tc_stats, backlog);
35
36         if (len < sizeof_tc_stats)
37                 return false;
38         else if (!umoven_or_printaddr(tcp, addr, sizeof_tc_stats, &st)) {
39                 PRINT_FIELD_U("{", st, bytes);
40                 PRINT_FIELD_U(", ", st, packets);
41                 PRINT_FIELD_U(", ", st, drops);
42                 PRINT_FIELD_U(", ", st, overlimits);
43                 PRINT_FIELD_U(", ", st, bps);
44                 PRINT_FIELD_U(", ", st, pps);
45                 PRINT_FIELD_U(", ", st, qlen);
46                 PRINT_FIELD_U(", ", st, backlog);
47                 tprints("}");
48         }
49
50         return true;
51 }
52
53 static bool
54 decode_tc_estimator(struct tcb *const tcp,
55                     const kernel_ulong_t addr,
56                     const unsigned int len,
57                     const void *const opaque_data)
58 {
59         struct tc_estimator est;
60
61         if (len < sizeof(est))
62                 return false;
63         else if (!umove_or_printaddr(tcp, addr, &est)) {
64                 PRINT_FIELD_D("{", est, interval);
65                 PRINT_FIELD_U(", ", est, ewma_log);
66                 tprints("}");
67         }
68
69         return true;
70 }
71
72 static bool
73 decode_gnet_stats_basic(struct tcb *const tcp,
74                         const kernel_ulong_t addr,
75                         const unsigned int len,
76                         const void *const opaque_data)
77 {
78 #ifdef HAVE_STRUCT_GNET_STATS_BASIC
79         struct gnet_stats_basic sb;
80         const unsigned int sizeof_st_basic =
81                 offsetofend(struct gnet_stats_basic, packets);
82
83         if (len < sizeof_st_basic)
84                 return false;
85         else if (!umoven_or_printaddr(tcp, addr, sizeof_st_basic, &sb)) {
86                 PRINT_FIELD_U("{", sb, bytes);
87                 PRINT_FIELD_U(", ", sb, packets);
88                 tprints("}");
89         }
90
91         return true;
92 #else
93         return false;
94 #endif
95 }
96
97 static bool
98 decode_gnet_stats_rate_est(struct tcb *const tcp,
99                            const kernel_ulong_t addr,
100                            const unsigned int len,
101                            const void *const opaque_data)
102 {
103 #ifdef HAVE_STRUCT_GNET_STATS_RATE_EST
104         struct gnet_stats_rate_est est;
105
106         if (len < sizeof(est))
107                 return false;
108         else if (!umove_or_printaddr(tcp, addr, &est)) {
109                 PRINT_FIELD_U("{", est, bps);
110                 PRINT_FIELD_U(", ", est, pps);
111                 tprints("}");
112         }
113
114         return true;
115 #else
116         return false;
117 #endif
118 }
119
120 static bool
121 decode_gnet_stats_queue(struct tcb *const tcp,
122                         const kernel_ulong_t addr,
123                         const unsigned int len,
124                         const void *const opaque_data)
125 {
126 #ifdef HAVE_STRUCT_GNET_STATS_QUEUE
127         struct gnet_stats_queue qstats;
128
129         if (len < sizeof(qstats))
130                 return false;
131         else if (!umove_or_printaddr(tcp, addr, &qstats)) {
132                 PRINT_FIELD_U("{", qstats, qlen);
133                 PRINT_FIELD_U(", ", qstats, backlog);
134                 PRINT_FIELD_U(", ", qstats, drops);
135                 PRINT_FIELD_U(", ", qstats, requeues);
136                 PRINT_FIELD_U(", ", qstats, overlimits);
137                 tprints("}");
138         }
139
140         return true;
141 #else
142         return false;
143 #endif
144 }
145
146 static bool
147 decode_gnet_stats_rate_est64(struct tcb *const tcp,
148                              const kernel_ulong_t addr,
149                              const unsigned int len,
150                              const void *const opaque_data)
151 {
152 #ifdef HAVE_STRUCT_GNET_STATS_RATE_EST64
153         struct gnet_stats_rate_est64 est;
154
155         if (len < sizeof(est))
156                 return false;
157         else if (!umove_or_printaddr(tcp, addr, &est)) {
158                 PRINT_FIELD_U("{", est, bps);
159                 PRINT_FIELD_U(", ", est, pps);
160                 tprints("}");
161         }
162
163         return true;
164 #else
165         return false;
166 #endif
167 }
168
169 static const nla_decoder_t tca_stats_nla_decoders[] = {
170         [TCA_STATS_BASIC]       = decode_gnet_stats_basic,
171         [TCA_STATS_RATE_EST]    = decode_gnet_stats_rate_est,
172         [TCA_STATS_QUEUE]       = decode_gnet_stats_queue,
173         [TCA_STATS_APP]         = NULL, /* unimplemented */
174         [TCA_STATS_RATE_EST64]  = decode_gnet_stats_rate_est64,
175         [TCA_STATS_PAD]         = NULL,
176         [TCA_STATS_BASIC_HW]    = decode_gnet_stats_basic,
177 };
178
179 bool
180 decode_nla_tc_stats(struct tcb *const tcp,
181                     const kernel_ulong_t addr,
182                     const unsigned int len,
183                     const void *const opaque_data)
184 {
185         decode_nlattr(tcp, addr, len, rtnl_tca_stats_attrs, "TCA_STATS_???",
186                       tca_stats_nla_decoders,
187                       ARRAY_SIZE(tca_stats_nla_decoders), opaque_data);
188
189         return true;
190 }
191
192 static bool
193 decode_tc_sizespec(struct tcb *const tcp,
194                    const kernel_ulong_t addr,
195                    const unsigned int len,
196                    const void *const opaque_data)
197 {
198 #ifdef HAVE_STRUCT_TC_SIZESPEC
199         struct tc_sizespec s;
200
201         if (len < sizeof(s))
202                 return false;
203         else if (!umove_or_printaddr(tcp, addr, &s)) {
204                 PRINT_FIELD_U("{", s, cell_log);
205                 PRINT_FIELD_U(", ", s, size_log);
206                 PRINT_FIELD_D(", ", s, cell_align);
207                 PRINT_FIELD_D(", ", s, overhead);
208                 PRINT_FIELD_U(", ", s, linklayer);
209                 PRINT_FIELD_U(", ", s, mpu);
210                 PRINT_FIELD_U(", ", s, mtu);
211                 PRINT_FIELD_U(", ", s, tsize);
212                 tprints("}");
213         }
214
215         return true;
216 #else
217         return false;
218 #endif
219 }
220
221 static bool
222 print_stab_data(struct tcb *const tcp, void *const elem_buf,
223                 const size_t elem_size, void *const opaque_data)
224 {
225         tprintf("%" PRIu16, *(uint16_t *) elem_buf);
226
227         return true;
228 }
229
230 static bool
231 decode_tca_stab_data(struct tcb *const tcp,
232                      const kernel_ulong_t addr,
233                      const unsigned int len,
234                      const void *const opaque_data)
235 {
236         uint16_t data;
237         const size_t nmemb = len / sizeof(data);
238
239         if (!nmemb)
240                 return false;
241
242         print_array(tcp, addr, nmemb, &data, sizeof(data),
243                     tfetch_mem, print_stab_data, NULL);
244
245         return true;
246 }
247
248 static const nla_decoder_t tca_stab_nla_decoders[] = {
249         [TCA_STAB_BASE] = decode_tc_sizespec,
250         [TCA_STAB_DATA] = decode_tca_stab_data
251 };
252
253 static bool
254 decode_tca_stab(struct tcb *const tcp,
255                 const kernel_ulong_t addr,
256                 const unsigned int len,
257                 const void *const opaque_data)
258 {
259         decode_nlattr(tcp, addr, len, rtnl_tca_stab_attrs, "TCA_STAB_???",
260                       tca_stab_nla_decoders,
261                       ARRAY_SIZE(tca_stab_nla_decoders), opaque_data);
262
263         return true;
264 }
265
266 static const nla_decoder_t tcmsg_nla_decoders[] = {
267         [TCA_KIND]              = decode_nla_str,
268         [TCA_OPTIONS]           = NULL, /* unimplemented */
269         [TCA_STATS]             = decode_tc_stats,
270         [TCA_XSTATS]            = NULL, /* unimplemented */
271         [TCA_RATE]              = decode_tc_estimator,
272         [TCA_FCNT]              = decode_nla_u32,
273         [TCA_STATS2]            = decode_nla_tc_stats,
274         [TCA_STAB]              = decode_tca_stab,
275         [TCA_PAD]               = NULL,
276         [TCA_DUMP_INVISIBLE]    = NULL,
277         [TCA_CHAIN]             = decode_nla_u32,
278         [TCA_HW_OFFLOAD]        = decode_nla_u8,
279         [TCA_INGRESS_BLOCK]     = decode_nla_u32,
280         [TCA_EGRESS_BLOCK]      = decode_nla_u32,
281 };
282
283 DECL_NETLINK_ROUTE_DECODER(decode_tcmsg)
284 {
285         struct tcmsg tcmsg = { .tcm_family = family };
286         size_t offset = sizeof(tcmsg.tcm_family);
287         bool decode_nla = false;
288
289         PRINT_FIELD_XVAL("{", tcmsg, tcm_family, addrfams, "AF_???");
290
291         tprints(", ");
292         if (len >= sizeof(tcmsg)) {
293                 if (!umoven_or_printaddr(tcp, addr + offset,
294                                          sizeof(tcmsg) - offset,
295                                          (char *) &tcmsg + offset)) {
296                         PRINT_FIELD_IFINDEX("", tcmsg, tcm_ifindex);
297                         PRINT_FIELD_U(", ", tcmsg, tcm_handle);
298                         PRINT_FIELD_U(", ", tcmsg, tcm_parent);
299                         PRINT_FIELD_U(", ", tcmsg, tcm_info);
300                         decode_nla = true;
301                 }
302         } else
303                 tprints("...");
304         tprints("}");
305
306         offset = NLMSG_ALIGN(sizeof(tcmsg));
307         if (decode_nla && len > offset) {
308                 tprints(", ");
309                 decode_nlattr(tcp, addr + offset, len - offset,
310                               rtnl_tc_attrs, "TCA_???", tcmsg_nla_decoders,
311                               ARRAY_SIZE(tcmsg_nla_decoders), NULL);
312         }
313 }