2017-08-13 10:22:29 +08:00
/*
* Copyright ( c ) 2016 Fabien Siron < fabien . siron @ epita . fr >
* Copyright ( c ) 2017 JingPiao Chen < chenjingpiao @ gmail . com >
2018-02-13 22:00:00 +00:00
* Copyright ( c ) 2016 - 2018 The strace developers .
2017-08-13 10:22:29 +08:00
* All rights reserved .
*
* Redistribution and use in source and binary forms , with or without
* modification , are permitted provided that the following conditions
* are met :
* 1. Redistributions of source code must retain the above copyright
* notice , this list of conditions and the following disclaimer .
* 2. Redistributions in binary form must reproduce the above copyright
* notice , this list of conditions and the following disclaimer in the
* documentation and / or other materials provided with the distribution .
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission .
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ` ` AS IS ' ' AND ANY EXPRESS OR
* IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED .
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT , INDIRECT ,
* INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES ( INCLUDING , BUT
* NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE ,
* DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY , OR TORT
* ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
*/
# include "defs.h"
# include "netlink_route.h"
2017-08-15 12:41:16 +08:00
# include "nlattr.h"
2017-08-13 10:22:29 +08:00
# include "print_fields.h"
# include "netlink.h"
rtnl_tc: decode tcmsg netlink attributes
* configure.ac (AC_CHECK_TYPES): Check for gnet_stats_basic,
gnet_stats_queue, gnet_stats_rate_est,
and gnet_stats_rate_est64 structures in <linux/gen_stats.h>.
And check for struct tc_sizespec in <linux/pkt_sched.h>.
* nlattr.h (tc_stats): New prototype.
* rtnl_tc.c: Include <linux/gen_stats.h>, <linux/pkt_sched.h>,
"xlat/rtnl_tca_stab_attrs.h" and "xlat/rtnl_tca_stats_attrs.h".
(decode_tc_stats, decode_tc_estimator, decode_gnet_stats_basic,
decode_gnet_stats_rate_est, decode_gnet_stats_queue,
decode_gnet_stats_rate_est64, decode_nla_tc_stats,
decode_tc_sizespec, print_stab_data, decode_tca_stab_data,
decode_tca_stab): New functions.
(tca_stats_nla_decoders, tca_stab_nla_decoders,
tcmsg_nla_decoders): New arrays.
(decode_tcmsg): Use tcmsg_nla_decoders.
* xlat/rtnl_tca_stab_attrs.in: New file.
* xlat/rtnl_tca_stats_attrs.in: Likewise.
2017-09-04 14:56:24 +08:00
# ifdef HAVE_STRUCT_GNET_STATS_BASIC
# include <linux / gen_stats.h>
# endif
# include <linux/pkt_sched.h>
2017-08-13 10:22:29 +08:00
# include <linux/rtnetlink.h>
2017-08-15 12:41:16 +08:00
# include "xlat/rtnl_tc_attrs.h"
rtnl_tc: decode tcmsg netlink attributes
* configure.ac (AC_CHECK_TYPES): Check for gnet_stats_basic,
gnet_stats_queue, gnet_stats_rate_est,
and gnet_stats_rate_est64 structures in <linux/gen_stats.h>.
And check for struct tc_sizespec in <linux/pkt_sched.h>.
* nlattr.h (tc_stats): New prototype.
* rtnl_tc.c: Include <linux/gen_stats.h>, <linux/pkt_sched.h>,
"xlat/rtnl_tca_stab_attrs.h" and "xlat/rtnl_tca_stats_attrs.h".
(decode_tc_stats, decode_tc_estimator, decode_gnet_stats_basic,
decode_gnet_stats_rate_est, decode_gnet_stats_queue,
decode_gnet_stats_rate_est64, decode_nla_tc_stats,
decode_tc_sizespec, print_stab_data, decode_tca_stab_data,
decode_tca_stab): New functions.
(tca_stats_nla_decoders, tca_stab_nla_decoders,
tcmsg_nla_decoders): New arrays.
(decode_tcmsg): Use tcmsg_nla_decoders.
* xlat/rtnl_tca_stab_attrs.in: New file.
* xlat/rtnl_tca_stats_attrs.in: Likewise.
2017-09-04 14:56:24 +08:00
# include "xlat/rtnl_tca_stab_attrs.h"
# include "xlat/rtnl_tca_stats_attrs.h"
static bool
decode_tc_stats ( struct tcb * const tcp ,
const kernel_ulong_t addr ,
const unsigned int len ,
const void * const opaque_data )
{
struct tc_stats st ;
const unsigned int sizeof_tc_stats =
offsetofend ( struct tc_stats , backlog ) ;
if ( len < sizeof_tc_stats )
return false ;
else if ( ! umoven_or_printaddr ( tcp , addr , sizeof_tc_stats , & st ) ) {
PRINT_FIELD_U ( " { " , st , bytes ) ;
PRINT_FIELD_U ( " , " , st , packets ) ;
PRINT_FIELD_U ( " , " , st , drops ) ;
PRINT_FIELD_U ( " , " , st , overlimits ) ;
PRINT_FIELD_U ( " , " , st , bps ) ;
PRINT_FIELD_U ( " , " , st , pps ) ;
PRINT_FIELD_U ( " , " , st , qlen ) ;
PRINT_FIELD_U ( " , " , st , backlog ) ;
tprints ( " } " ) ;
}
return true ;
}
static bool
decode_tc_estimator ( struct tcb * const tcp ,
const kernel_ulong_t addr ,
const unsigned int len ,
const void * const opaque_data )
{
struct tc_estimator est ;
if ( len < sizeof ( est ) )
return false ;
else if ( ! umove_or_printaddr ( tcp , addr , & est ) ) {
PRINT_FIELD_D ( " { " , est , interval ) ;
PRINT_FIELD_U ( " , " , est , ewma_log ) ;
tprints ( " } " ) ;
}
return true ;
}
static bool
decode_gnet_stats_basic ( struct tcb * const tcp ,
const kernel_ulong_t addr ,
const unsigned int len ,
const void * const opaque_data )
{
# ifdef HAVE_STRUCT_GNET_STATS_BASIC
struct gnet_stats_basic sb ;
const unsigned int sizeof_st_basic =
offsetofend ( struct gnet_stats_basic , packets ) ;
if ( len < sizeof_st_basic )
return false ;
else if ( ! umoven_or_printaddr ( tcp , addr , sizeof_st_basic , & sb ) ) {
PRINT_FIELD_U ( " { " , sb , bytes ) ;
PRINT_FIELD_U ( " , " , sb , packets ) ;
tprints ( " } " ) ;
}
return true ;
# else
return false ;
# endif
}
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 )
{
# ifdef HAVE_STRUCT_GNET_STATS_RATE_EST
struct gnet_stats_rate_est est ;
if ( len < sizeof ( est ) )
return false ;
else if ( ! umove_or_printaddr ( tcp , addr , & est ) ) {
PRINT_FIELD_U ( " { " , est , bps ) ;
PRINT_FIELD_U ( " , " , est , pps ) ;
tprints ( " } " ) ;
}
return true ;
# else
return false ;
# endif
}
static bool
decode_gnet_stats_queue ( struct tcb * const tcp ,
const kernel_ulong_t addr ,
const unsigned int len ,
const void * const opaque_data )
{
# ifdef HAVE_STRUCT_GNET_STATS_QUEUE
struct gnet_stats_queue qstats ;
if ( len < sizeof ( qstats ) )
return false ;
else if ( ! umove_or_printaddr ( tcp , addr , & qstats ) ) {
PRINT_FIELD_U ( " { " , qstats , qlen ) ;
PRINT_FIELD_U ( " , " , qstats , backlog ) ;
PRINT_FIELD_U ( " , " , qstats , drops ) ;
PRINT_FIELD_U ( " , " , qstats , requeues ) ;
PRINT_FIELD_U ( " , " , qstats , overlimits ) ;
tprints ( " } " ) ;
}
return true ;
# else
return false ;
# endif
}
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 )
{
# ifdef HAVE_STRUCT_GNET_STATS_RATE_EST64
struct gnet_stats_rate_est64 est ;
if ( len < sizeof ( est ) )
return false ;
else if ( ! umove_or_printaddr ( tcp , addr , & est ) ) {
PRINT_FIELD_U ( " { " , est , bps ) ;
PRINT_FIELD_U ( " , " , est , pps ) ;
tprints ( " } " ) ;
}
return true ;
# else
return false ;
# endif
}
static const nla_decoder_t tca_stats_nla_decoders [ ] = {
[ TCA_STATS_BASIC ] = decode_gnet_stats_basic ,
[ TCA_STATS_RATE_EST ] = decode_gnet_stats_rate_est ,
[ TCA_STATS_QUEUE ] = decode_gnet_stats_queue ,
[ TCA_STATS_APP ] = NULL , /* unimplemented */
[ TCA_STATS_RATE_EST64 ] = decode_gnet_stats_rate_est64 ,
[ TCA_STATS_PAD ] = NULL ,
} ;
bool
decode_nla_tc_stats ( struct tcb * const tcp ,
const kernel_ulong_t addr ,
const unsigned int len ,
const void * const opaque_data )
{
decode_nlattr ( tcp , addr , len , rtnl_tca_stats_attrs , " TCA_STATS_??? " ,
tca_stats_nla_decoders ,
ARRAY_SIZE ( tca_stats_nla_decoders ) , opaque_data ) ;
return true ;
}
static bool
decode_tc_sizespec ( struct tcb * const tcp ,
const kernel_ulong_t addr ,
const unsigned int len ,
const void * const opaque_data )
{
# ifdef HAVE_STRUCT_TC_SIZESPEC
struct tc_sizespec s ;
if ( len < sizeof ( s ) )
return false ;
else if ( ! umove_or_printaddr ( tcp , addr , & s ) ) {
PRINT_FIELD_U ( " { " , s , cell_log ) ;
PRINT_FIELD_U ( " , " , s , size_log ) ;
PRINT_FIELD_D ( " , " , s , cell_align ) ;
PRINT_FIELD_D ( " , " , s , overhead ) ;
PRINT_FIELD_U ( " , " , s , linklayer ) ;
PRINT_FIELD_U ( " , " , s , mpu ) ;
PRINT_FIELD_U ( " , " , s , mtu ) ;
PRINT_FIELD_U ( " , " , s , tsize ) ;
tprints ( " } " ) ;
}
return true ;
# else
return false ;
# endif
}
static bool
print_stab_data ( struct tcb * const tcp , void * const elem_buf ,
const size_t elem_size , void * const opaque_data )
{
tprintf ( " % " PRIu16 , * ( uint16_t * ) elem_buf ) ;
return true ;
}
static bool
decode_tca_stab_data ( struct tcb * const tcp ,
const kernel_ulong_t addr ,
const unsigned int len ,
const void * const opaque_data )
{
uint16_t data ;
const size_t nmemb = len / sizeof ( data ) ;
if ( ! nmemb )
return false ;
print_array ( tcp , addr , nmemb , & data , sizeof ( data ) ,
print_array: enhance printing of unfetchable object addresses
When umoven_func invocation fails to fetch data, it prints the faulty
address. If this happens to a subsequent umoven_func invocation,
the printed address may be undistinguishable from a valid data printed
by print_func, e.g. when the data is printed in a numeric form like
[0x1, 0x2, 0x3, 0xdefaced].
Fix this source of confusion by moving the printing of the faulty
address from umoven_func to print_array itself. This change renames
umoven_func to tfetch_mem_func and changes its semantics, so that
- tfetch_mem_func never prints anything;
- tfetch_mem_func returns true if the fetch succeeded,
and false otherwise.
* defs.h (print_array): Replace umoven_func argument with
tfetch_mem_func.
* util.c (print_array): Replace umoven_func argument with
tfetch_mem_func, document expected tfetch_mem_func return value
semantics. When tfetch_mem_func returns false, print either addr
or "... /* addr */" depending on the context (inside the array or not).
* bpf.c (print_ebpf_prog, print_bpf_prog_info,
BEGIN_BPF_CMD_DECODER(BPF_PROG_QUERY)): Replace umoven_or_printaddr
argument of print_array with tfetch_mem.
* bpf_filter.c (print_bpf_fprog): Likewise.
* btrfs.c (btrfs_print_logical_ino_container,
btrfs_print_ino_path_container, btrfs_print_qgroup_inherit,
btrfs_ioctl): Likewise.
* dm.c (dm_decode_dm_target_deps): Likewise.
* epoll.c (epoll_wait_common): Likewise.
* file_ioctl.c (file_ioctl): Likewise.
* ipc_sem.c (tprint_sembuf_array): Likewise.
* kexec.c (print_kexec_segments): Likewise.
* mem.c (SYS_FUNC(subpage_prot)): Likewise.
* net.c (print_getsockopt): Likewise.
* netlink.c (decode_nlmsgerr_attr_cookie): Likewise.
* netlink_netlink_diag.c (decode_netlink_diag_groups): Likewise.
* netlink_packet_diag.c (decode_packet_diag_mclist): Likewise.
* netlink_unix_diag.c (decode_unix_diag_inode): Likewise.
* nlattr.c (decode_nla_meminfo): Likewise.
* numa.c (print_nodemask, SYS_FUNC(move_pages),
* perf_ioctl.c (perf_ioctl_query_bpf): Likewise.
* poll.c (decode_poll_entering): Likewise.
* printsiginfo.c (print_siginfo_array): Likewise.
* rtnl_tc.c (decode_tca_stab_data): Likewise.
* sock.c (decode_ifconf): Likewise.
* uid.c (print_groups): Likewise.
* io.c (SYS_FUNC(io_submit), SYS_FUNC(io_getevents)): Replace
umoven_or_printaddr argument of print_array with tfetch_mem.
(tprint_iov_upto): Replace umoven_or_printaddr_ignore_syserror
with tfetch_mem_ignore_syserror.
* v4l2.c (print_v4l2_format_fmt): Replace umoven_or_printaddr argument
of print_array with tfetch_mem.
(print_v4l2_ext_controls): Replace umoven_or_printaddr_ignore_syserror
with tfetch_mem_ignore_syserror.
* mmsghdr.c (fetch_struct_mmsghdr_or_printaddr): Rename
to fetch_struct_mmsghdr_for_print, do not print address, return bool.
(decode_mmsgvec): Replace fetch_struct_mmsghdr_or_printaddr
with fetch_struct_mmsghdr_for_print.
* tests/aio.c (main): Update expected output.
* tests/bpf.c (print_BPF_PROG_QUERY_attr5): Likewise.
* tests/ioctl_perf-success.c (main): Likewise.
* tests/ioctl_v4l2.c (main): Update expected output.
* tests/kexec_load.c (main): Likewise.
* tests/mmsg_name.c (test_mmsg_name): Update expected output.
* tests/move_pages.c (print_page_array, print_node_array): Likewise.
* tests/poll.c (print_pollfd_array_entering): Likewise.
* tests/preadv-pwritev.c (main): Likewise.
* tests/preadv2-pwritev2.c (dumpio): Likewise.
* tests/process_vm_readv_writev.c (print_iov): Likewise.
* tests/pwritev.c (print_iovec): Likewise.
* tests/readv.c (main): Likewise.
* tests/seccomp-filter-v.c
* tests/semop.c (main): Likewise.
* tests/set_mempolicy.c (print_nodes): Likewise.
* tests/setgroups.c (main): Likewise.
* tests/test_nlattr.h (print_nlattr) Likewise.
Co-Authored-by: Eugene Syromyatnikov <evgsyr@gmail.com>
2018-05-29 01:15:19 +00:00
tfetch_mem , print_stab_data , NULL ) ;
rtnl_tc: decode tcmsg netlink attributes
* configure.ac (AC_CHECK_TYPES): Check for gnet_stats_basic,
gnet_stats_queue, gnet_stats_rate_est,
and gnet_stats_rate_est64 structures in <linux/gen_stats.h>.
And check for struct tc_sizespec in <linux/pkt_sched.h>.
* nlattr.h (tc_stats): New prototype.
* rtnl_tc.c: Include <linux/gen_stats.h>, <linux/pkt_sched.h>,
"xlat/rtnl_tca_stab_attrs.h" and "xlat/rtnl_tca_stats_attrs.h".
(decode_tc_stats, decode_tc_estimator, decode_gnet_stats_basic,
decode_gnet_stats_rate_est, decode_gnet_stats_queue,
decode_gnet_stats_rate_est64, decode_nla_tc_stats,
decode_tc_sizespec, print_stab_data, decode_tca_stab_data,
decode_tca_stab): New functions.
(tca_stats_nla_decoders, tca_stab_nla_decoders,
tcmsg_nla_decoders): New arrays.
(decode_tcmsg): Use tcmsg_nla_decoders.
* xlat/rtnl_tca_stab_attrs.in: New file.
* xlat/rtnl_tca_stats_attrs.in: Likewise.
2017-09-04 14:56:24 +08:00
return true ;
}
static const nla_decoder_t tca_stab_nla_decoders [ ] = {
[ TCA_STAB_BASE ] = decode_tc_sizespec ,
[ TCA_STAB_DATA ] = decode_tca_stab_data
} ;
static bool
decode_tca_stab ( struct tcb * const tcp ,
const kernel_ulong_t addr ,
const unsigned int len ,
const void * const opaque_data )
{
decode_nlattr ( tcp , addr , len , rtnl_tca_stab_attrs , " TCA_STAB_??? " ,
tca_stab_nla_decoders ,
ARRAY_SIZE ( tca_stab_nla_decoders ) , opaque_data ) ;
return true ;
}
static const nla_decoder_t tcmsg_nla_decoders [ ] = {
[ TCA_KIND ] = decode_nla_str ,
[ TCA_OPTIONS ] = NULL , /* unimplemented */
[ TCA_STATS ] = decode_tc_stats ,
[ TCA_XSTATS ] = NULL , /* unimplemented */
[ TCA_RATE ] = decode_tc_estimator ,
[ TCA_FCNT ] = decode_nla_u32 ,
[ TCA_STATS2 ] = decode_nla_tc_stats ,
[ TCA_STAB ] = decode_tca_stab ,
[ TCA_PAD ] = NULL ,
[ TCA_DUMP_INVISIBLE ] = NULL ,
2018-02-12 20:26:32 +01:00
[ TCA_CHAIN ] = decode_nla_u32 ,
[ TCA_HW_OFFLOAD ] = decode_nla_u8 ,
[ TCA_INGRESS_BLOCK ] = decode_nla_u32 ,
[ TCA_EGRESS_BLOCK ] = decode_nla_u32 ,
rtnl_tc: decode tcmsg netlink attributes
* configure.ac (AC_CHECK_TYPES): Check for gnet_stats_basic,
gnet_stats_queue, gnet_stats_rate_est,
and gnet_stats_rate_est64 structures in <linux/gen_stats.h>.
And check for struct tc_sizespec in <linux/pkt_sched.h>.
* nlattr.h (tc_stats): New prototype.
* rtnl_tc.c: Include <linux/gen_stats.h>, <linux/pkt_sched.h>,
"xlat/rtnl_tca_stab_attrs.h" and "xlat/rtnl_tca_stats_attrs.h".
(decode_tc_stats, decode_tc_estimator, decode_gnet_stats_basic,
decode_gnet_stats_rate_est, decode_gnet_stats_queue,
decode_gnet_stats_rate_est64, decode_nla_tc_stats,
decode_tc_sizespec, print_stab_data, decode_tca_stab_data,
decode_tca_stab): New functions.
(tca_stats_nla_decoders, tca_stab_nla_decoders,
tcmsg_nla_decoders): New arrays.
(decode_tcmsg): Use tcmsg_nla_decoders.
* xlat/rtnl_tca_stab_attrs.in: New file.
* xlat/rtnl_tca_stats_attrs.in: Likewise.
2017-09-04 14:56:24 +08:00
} ;
2017-08-15 12:41:16 +08:00
2017-08-13 10:22:29 +08:00
DECL_NETLINK_ROUTE_DECODER ( decode_tcmsg )
{
struct tcmsg tcmsg = { . tcm_family = family } ;
2017-08-15 12:41:16 +08:00
size_t offset = sizeof ( tcmsg . tcm_family ) ;
bool decode_nla = false ;
2017-08-13 10:22:29 +08:00
PRINT_FIELD_XVAL ( " { " , tcmsg , tcm_family , addrfams , " AF_??? " ) ;
tprints ( " , " ) ;
if ( len > = sizeof ( tcmsg ) ) {
if ( ! umoven_or_printaddr ( tcp , addr + offset ,
sizeof ( tcmsg ) - offset ,
2018-01-22 13:24:40 +01:00
( char * ) & tcmsg + offset ) ) {
2017-08-13 10:22:29 +08:00
PRINT_FIELD_IFINDEX ( " " , tcmsg , tcm_ifindex ) ;
PRINT_FIELD_U ( " , " , tcmsg , tcm_handle ) ;
PRINT_FIELD_U ( " , " , tcmsg , tcm_parent ) ;
PRINT_FIELD_U ( " , " , tcmsg , tcm_info ) ;
2017-08-15 12:41:16 +08:00
decode_nla = true ;
2017-08-13 10:22:29 +08:00
}
} else
tprints ( " ... " ) ;
tprints ( " } " ) ;
2017-08-15 12:41:16 +08:00
offset = NLMSG_ALIGN ( sizeof ( tcmsg ) ) ;
if ( decode_nla & & len > offset ) {
tprints ( " , " ) ;
decode_nlattr ( tcp , addr + offset , len - offset ,
rtnl_tc: decode tcmsg netlink attributes
* configure.ac (AC_CHECK_TYPES): Check for gnet_stats_basic,
gnet_stats_queue, gnet_stats_rate_est,
and gnet_stats_rate_est64 structures in <linux/gen_stats.h>.
And check for struct tc_sizespec in <linux/pkt_sched.h>.
* nlattr.h (tc_stats): New prototype.
* rtnl_tc.c: Include <linux/gen_stats.h>, <linux/pkt_sched.h>,
"xlat/rtnl_tca_stab_attrs.h" and "xlat/rtnl_tca_stats_attrs.h".
(decode_tc_stats, decode_tc_estimator, decode_gnet_stats_basic,
decode_gnet_stats_rate_est, decode_gnet_stats_queue,
decode_gnet_stats_rate_est64, decode_nla_tc_stats,
decode_tc_sizespec, print_stab_data, decode_tca_stab_data,
decode_tca_stab): New functions.
(tca_stats_nla_decoders, tca_stab_nla_decoders,
tcmsg_nla_decoders): New arrays.
(decode_tcmsg): Use tcmsg_nla_decoders.
* xlat/rtnl_tca_stab_attrs.in: New file.
* xlat/rtnl_tca_stats_attrs.in: Likewise.
2017-09-04 14:56:24 +08:00
rtnl_tc_attrs , " TCA_??? " , tcmsg_nla_decoders ,
ARRAY_SIZE ( tcmsg_nla_decoders ) , NULL ) ;
2017-08-15 12:41:16 +08:00
}
2017-08-13 10:22:29 +08:00
}