1 /* 2 * Copyright (c) 2016 Fabien Siron <fabien.siron (at) epita.fr> 3 * Copyright (c) 2017 JingPiao Chen <chenjingpiao (at) 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 } 333