2017-08-13 05:22:29 +03:00
/*
* Copyright ( c ) 2016 Fabien Siron < fabien . siron @ epita . fr >
* Copyright ( c ) 2017 JingPiao Chen < chenjingpiao @ gmail . com >
* Copyright ( c ) 2016 - 2017 The strace developers .
* 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 07:41:16 +03:00
# include "nlattr.h"
2017-08-13 05:22:29 +03: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 09:56:24 +03:00
# ifdef HAVE_STRUCT_GNET_STATS_BASIC
# include <linux / gen_stats.h>
# endif
# include <linux/pkt_sched.h>
2017-08-13 05:22:29 +03:00
# include <linux/rtnetlink.h>
2017-08-15 07:41:16 +03: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 09:56:24 +03: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 ) ,
umoven_or_printaddr , print_stab_data , NULL ) ;
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 ,
[ TCA_CHAIN ] = decode_nla_u32
} ;
2017-08-15 07:41:16 +03:00
2017-08-13 05:22:29 +03:00
DECL_NETLINK_ROUTE_DECODER ( decode_tcmsg )
{
struct tcmsg tcmsg = { . tcm_family = family } ;
2017-08-15 07:41:16 +03:00
size_t offset = sizeof ( tcmsg . tcm_family ) ;
bool decode_nla = false ;
2017-08-13 05:22:29 +03:00
PRINT_FIELD_XVAL ( " { " , tcmsg , tcm_family , addrfams , " AF_??? " ) ;
tprints ( " , " ) ;
if ( len > = sizeof ( tcmsg ) ) {
if ( ! umoven_or_printaddr ( tcp , addr + offset ,
sizeof ( tcmsg ) - offset ,
( void * ) & tcmsg + offset ) ) {
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 07:41:16 +03:00
decode_nla = true ;
2017-08-13 05:22:29 +03:00
}
} else
tprints ( " ... " ) ;
tprints ( " } " ) ;
2017-08-15 07:41:16 +03: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 09:56:24 +03:00
rtnl_tc_attrs , " TCA_??? " , tcmsg_nla_decoders ,
ARRAY_SIZE ( tcmsg_nla_decoders ) , NULL ) ;
2017-08-15 07:41:16 +03:00
}
2017-08-13 05:22:29 +03:00
}