]> granicus.if.org Git - strace/blob - rtnl_tc.c
nlattr: add UID/GID netlink attribute decoders
[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  * 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
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
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
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
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
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
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
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
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
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
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
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
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 }