(root)/
strace-6.5/
src/
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-2023 The strace developers.
       5   * All rights reserved.
       6   *
       7   * SPDX-License-Identifier: LGPL-2.1-or-later
       8   */
       9  
      10  #include "defs.h"
      11  #include "netlink_route.h"
      12  #include "nlattr.h"
      13  
      14  #include "netlink.h"
      15  #include <linux/gen_stats.h>
      16  #include <linux/pkt_sched.h>
      17  #include <linux/rtnetlink.h>
      18  
      19  #include "xlat/rtnl_tc_attrs.h"
      20  #include "xlat/rtnl_tca_stab_attrs.h"
      21  #include "xlat/rtnl_tca_stats_attrs.h"
      22  
      23  static bool
      24  decode_tc_stats(struct tcb *const tcp,
      25  		const kernel_ulong_t addr,
      26  		const unsigned int len,
      27  		const void *const opaque_data)
      28  {
      29  	struct tc_stats st;
      30  	const unsigned int sizeof_tc_stats =
      31  		offsetofend(struct tc_stats, backlog);
      32  
      33  	if (len < sizeof_tc_stats)
      34  		return false;
      35  	else if (!umoven_or_printaddr(tcp, addr, sizeof_tc_stats, &st)) {
      36  		tprint_struct_begin();
      37  		PRINT_FIELD_U(st, bytes);
      38  		tprint_struct_next();
      39  		PRINT_FIELD_U(st, packets);
      40  		tprint_struct_next();
      41  		PRINT_FIELD_U(st, drops);
      42  		tprint_struct_next();
      43  		PRINT_FIELD_U(st, overlimits);
      44  		tprint_struct_next();
      45  		PRINT_FIELD_U(st, bps);
      46  		tprint_struct_next();
      47  		PRINT_FIELD_U(st, pps);
      48  		tprint_struct_next();
      49  		PRINT_FIELD_U(st, qlen);
      50  		tprint_struct_next();
      51  		PRINT_FIELD_U(st, backlog);
      52  		tprint_struct_end();
      53  	}
      54  
      55  	return true;
      56  }
      57  
      58  static bool
      59  decode_tc_estimator(struct tcb *const tcp,
      60  		    const kernel_ulong_t addr,
      61  		    const unsigned int len,
      62  		    const void *const opaque_data)
      63  {
      64  	struct tc_estimator est;
      65  
      66  	if (len < sizeof(est))
      67  		return false;
      68  	else if (!umove_or_printaddr(tcp, addr, &est)) {
      69  		tprint_struct_begin();
      70  		PRINT_FIELD_D(est, interval);
      71  		tprint_struct_next();
      72  		PRINT_FIELD_U(est, ewma_log);
      73  		tprint_struct_end();
      74  	}
      75  
      76  	return true;
      77  }
      78  
      79  static bool
      80  decode_gnet_stats_basic(struct tcb *const tcp,
      81  			const kernel_ulong_t addr,
      82  			const unsigned int len,
      83  			const void *const opaque_data)
      84  {
      85  	struct gnet_stats_basic sb;
      86  	const unsigned int sizeof_st_basic =
      87  		offsetofend(struct gnet_stats_basic, packets);
      88  
      89  	if (len < sizeof_st_basic)
      90  		return false;
      91  	else if (!umoven_or_printaddr(tcp, addr, sizeof_st_basic, &sb)) {
      92  		tprint_struct_begin();
      93  		PRINT_FIELD_U(sb, bytes);
      94  		tprint_struct_next();
      95  		PRINT_FIELD_U(sb, packets);
      96  		tprint_struct_end();
      97  	}
      98  
      99  	return true;
     100  }
     101  
     102  static bool
     103  decode_gnet_stats_rate_est(struct tcb *const tcp,
     104  			   const kernel_ulong_t addr,
     105  			   const unsigned int len,
     106  			   const void *const opaque_data)
     107  {
     108  	struct gnet_stats_rate_est est;
     109  
     110  	if (len < sizeof(est))
     111  		return false;
     112  	else if (!umove_or_printaddr(tcp, addr, &est)) {
     113  		tprint_struct_begin();
     114  		PRINT_FIELD_U(est, bps);
     115  		tprint_struct_next();
     116  		PRINT_FIELD_U(est, pps);
     117  		tprint_struct_end();
     118  	}
     119  
     120  	return true;
     121  }
     122  
     123  static bool
     124  decode_gnet_stats_queue(struct tcb *const tcp,
     125  			const kernel_ulong_t addr,
     126  			const unsigned int len,
     127  			const void *const opaque_data)
     128  {
     129  	struct gnet_stats_queue qstats;
     130  
     131  	if (len < sizeof(qstats))
     132  		return false;
     133  	else if (!umove_or_printaddr(tcp, addr, &qstats)) {
     134  		tprint_struct_begin();
     135  		PRINT_FIELD_U(qstats, qlen);
     136  		tprint_struct_next();
     137  		PRINT_FIELD_U(qstats, backlog);
     138  		tprint_struct_next();
     139  		PRINT_FIELD_U(qstats, drops);
     140  		tprint_struct_next();
     141  		PRINT_FIELD_U(qstats, requeues);
     142  		tprint_struct_next();
     143  		PRINT_FIELD_U(qstats, overlimits);
     144  		tprint_struct_end();
     145  	}
     146  
     147  	return true;
     148  }
     149  
     150  static bool
     151  decode_gnet_stats_rate_est64(struct tcb *const tcp,
     152  			     const kernel_ulong_t addr,
     153  			     const unsigned int len,
     154  			     const void *const opaque_data)
     155  {
     156  	struct gnet_stats_rate_est64 est;
     157  
     158  	if (len < sizeof(est))
     159  		return false;
     160  	else if (!umove_or_printaddr(tcp, addr, &est)) {
     161  		tprint_struct_begin();
     162  		PRINT_FIELD_U(est, bps);
     163  		tprint_struct_next();
     164  		PRINT_FIELD_U(est, pps);
     165  		tprint_struct_end();
     166  	}
     167  
     168  	return true;
     169  }
     170  
     171  static const nla_decoder_t tca_stats_nla_decoders[] = {
     172  	[TCA_STATS_BASIC]	= decode_gnet_stats_basic,
     173  	[TCA_STATS_RATE_EST]	= decode_gnet_stats_rate_est,
     174  	[TCA_STATS_QUEUE]	= decode_gnet_stats_queue,
     175  	[TCA_STATS_APP]		= NULL, /* unimplemented */
     176  	[TCA_STATS_RATE_EST64]	= decode_gnet_stats_rate_est64,
     177  	[TCA_STATS_PAD]		= NULL,
     178  	[TCA_STATS_BASIC_HW]	= decode_gnet_stats_basic,
     179  	[TCA_STATS_PKT64]	= decode_nla_u64,
     180  };
     181  
     182  bool
     183  decode_nla_tc_stats(struct tcb *const tcp,
     184  		    const kernel_ulong_t addr,
     185  		    const unsigned int len,
     186  		    const void *const opaque_data)
     187  {
     188  	decode_nlattr(tcp, addr, len, rtnl_tca_stats_attrs, "TCA_STATS_???",
     189  		      tca_stats_nla_decoders,
     190  		      ARRAY_SIZE(tca_stats_nla_decoders), opaque_data);
     191  
     192  	return true;
     193  }
     194  
     195  static bool
     196  decode_tc_sizespec(struct tcb *const tcp,
     197  		   const kernel_ulong_t addr,
     198  		   const unsigned int len,
     199  		   const void *const opaque_data)
     200  {
     201  	struct tc_sizespec s;
     202  
     203  	if (len < sizeof(s))
     204  		return false;
     205  	else if (!umove_or_printaddr(tcp, addr, &s)) {
     206  		tprint_struct_begin();
     207  		PRINT_FIELD_U(s, cell_log);
     208  		tprint_struct_next();
     209  		PRINT_FIELD_U(s, size_log);
     210  		tprint_struct_next();
     211  		PRINT_FIELD_D(s, cell_align);
     212  		tprint_struct_next();
     213  		PRINT_FIELD_D(s, overhead);
     214  		tprint_struct_next();
     215  		PRINT_FIELD_U(s, linklayer);
     216  		tprint_struct_next();
     217  		PRINT_FIELD_U(s, mpu);
     218  		tprint_struct_next();
     219  		PRINT_FIELD_U(s, mtu);
     220  		tprint_struct_next();
     221  		PRINT_FIELD_U(s, tsize);
     222  		tprint_struct_end();
     223  	}
     224  
     225  	return true;
     226  }
     227  
     228  static bool
     229  print_stab_data(struct tcb *const tcp, void *const elem_buf,
     230  		const size_t elem_size, void *const opaque_data)
     231  {
     232  	PRINT_VAL_U(*(uint16_t *) elem_buf);
     233  
     234  	return true;
     235  }
     236  
     237  static bool
     238  decode_tca_stab_data(struct tcb *const tcp,
     239  		     const kernel_ulong_t addr,
     240  		     const unsigned int len,
     241  		     const void *const opaque_data)
     242  {
     243  	uint16_t data;
     244  	const size_t nmemb = len / sizeof(data);
     245  
     246  	if (!nmemb)
     247  		return false;
     248  
     249  	print_array(tcp, addr, nmemb, &data, sizeof(data),
     250  		    tfetch_mem, print_stab_data, NULL);
     251  
     252  	return true;
     253  }
     254  
     255  static const nla_decoder_t tca_stab_nla_decoders[] = {
     256  	[TCA_STAB_BASE]	= decode_tc_sizespec,
     257  	[TCA_STAB_DATA] = decode_tca_stab_data
     258  };
     259  
     260  static bool
     261  decode_tca_stab(struct tcb *const tcp,
     262  		const kernel_ulong_t addr,
     263  		const unsigned int len,
     264  		const void *const opaque_data)
     265  {
     266  	decode_nlattr(tcp, addr, len, rtnl_tca_stab_attrs, "TCA_STAB_???",
     267  		      tca_stab_nla_decoders,
     268  		      ARRAY_SIZE(tca_stab_nla_decoders), opaque_data);
     269  
     270  	return true;
     271  }
     272  
     273  static const nla_decoder_t tcmsg_nla_decoders[] = {
     274  	[TCA_KIND]		= decode_nla_str,
     275  	[TCA_OPTIONS]		= NULL, /* unimplemented */
     276  	[TCA_STATS]		= decode_tc_stats,
     277  	[TCA_XSTATS]		= NULL, /* unimplemented */
     278  	[TCA_RATE]		= decode_tc_estimator,
     279  	[TCA_FCNT]		= decode_nla_u32,
     280  	[TCA_STATS2]		= decode_nla_tc_stats,
     281  	[TCA_STAB]		= decode_tca_stab,
     282  	[TCA_PAD]		= NULL,
     283  	[TCA_DUMP_INVISIBLE]	= NULL,
     284  	[TCA_CHAIN]		= decode_nla_u32,
     285  	[TCA_HW_OFFLOAD]	= decode_nla_u8,
     286  	[TCA_INGRESS_BLOCK]	= decode_nla_u32,
     287  	[TCA_EGRESS_BLOCK]	= decode_nla_u32,
     288  	[TCA_DUMP_FLAGS]	= decode_nla_u32,
     289  	[TCA_EXT_WARN_MSG]	= decode_nla_str,
     290  };
     291  
     292  DECL_NETLINK_ROUTE_DECODER(decode_tcmsg)
     293  {
     294  	struct tcmsg tcmsg = { .tcm_family = family };
     295  	size_t offset = sizeof(tcmsg.tcm_family);
     296  	bool decode_nla = false;
     297  
     298  	tprint_struct_begin();
     299  	PRINT_FIELD_XVAL(tcmsg, tcm_family, addrfams, "AF_???");
     300  	tprint_struct_next();
     301  
     302  	if (len >= sizeof(tcmsg)) {
     303  		if (!umoven_or_printaddr(tcp, addr + offset,
     304  					 sizeof(tcmsg) - offset,
     305  					 (char *) &tcmsg + offset)) {
     306  			PRINT_FIELD_IFINDEX(tcmsg, tcm_ifindex);
     307  			tprint_struct_next();
     308  			PRINT_FIELD_U(tcmsg, tcm_handle);
     309  			tprint_struct_next();
     310  			PRINT_FIELD_U(tcmsg, tcm_parent);
     311  			tprint_struct_next();
     312  			PRINT_FIELD_U(tcmsg, tcm_info);
     313  			decode_nla = true;
     314  		}
     315  	} else
     316  		tprint_more_data_follows();
     317  	tprint_struct_end();
     318  
     319  	offset = NLMSG_ALIGN(sizeof(tcmsg));
     320  	if (decode_nla && len > offset) {
     321  		tprint_array_next();
     322  		decode_nlattr(tcp, addr + offset, len - offset,
     323  			      rtnl_tc_attrs, "TCA_???", tcmsg_nla_decoders,
     324  			      ARRAY_SIZE(tcmsg_nla_decoders), NULL);
     325  	}
     326  }