Home | History | Annotate | Download | only in strace
      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