On Sat, Aug 19, 2017 at 09:50:10AM +0800, JingPiao Chen wrote: > * configure.ac (AC_CHECK_HEADERS): Add linux/if_link.h. > (AC_CHECK_TYPES): Check for struct rtnl_link_stats64 in linux/if_link.h. > (AC_CHECK_MEMBERS): Check for rx_nohandler field > in struct rtnl_link_stats and struct rtnl_link_stats64. > * rtnl_link.c: Include <arpa/inet.h>, <linux/if_arp.h>, > <linux/if_link.h> and <linux/netdevice.h>. > (min_ifla_address_len, ifla_address_default_decoder, > ifla_address_type_specific_decoder, > decode_ifla_address, decode_rtnl_link_stats, > decode_rtnl_link_ifmap, decode_rtnl_link_stats64, > print_item_id, decode_ifla_phys_item_id): New functions. > (decode_ifla_phys_item_id): New array.
How could decode_ifla_phys_item_id be both a function and an array? > (decode_ifinfomsg): Use it. > --- > configure.ac | 6 ++ > rtnl_link.c | 298 > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- > 2 files changed, 303 insertions(+), 1 deletion(-) > > diff --git a/configure.ac b/configure.ac > index cb398fb..dacd67f 100644 > --- a/configure.ac > +++ b/configure.ac > @@ -382,6 +382,7 @@ AC_CHECK_HEADERS(m4_normalize([ > linux/genetlink.h > linux/hiddev.h > linux/if_addr.h > + linux/if_link.h > linux/ip_vs.h > linux/ipc.h > linux/mmtimer.h > @@ -447,6 +448,11 @@ AC_CHECK_TYPES([struct dcbmsg],,, [#include > <linux/dcbnl.h>]) > AC_CHECK_TYPES([struct ifaddrlblmsg],,, [#include <linux/if_addrlabel.h>]) > AC_CHECK_TYPES([struct netconfmsg],,, [#include <linux/netconf.h>]) > > +AC_CHECK_TYPES([struct rtnl_link_stats64], [ > + AC_CHECK_MEMBERS([struct rtnl_link_stats64.rx_nohandler],,, [#include > <linux/if_link.h>]) > +],, [#include <linux/if_link.h>]) > +AC_CHECK_MEMBERS([struct rtnl_link_stats.rx_nohandler],,, [#include > <linux/if_link.h>]) > + > AC_CHECK_TYPES([struct statfs], [ > AC_CHECK_MEMBERS([struct statfs.f_frsize],,, [#include <linux/types.h> > #include <asm/statfs.h>]) > diff --git a/rtnl_link.c b/rtnl_link.c > index 18897f3..29c2e19 100644 > --- a/rtnl_link.c > +++ b/rtnl_link.c > @@ -32,11 +32,305 @@ > #include "nlattr.h" > #include "print_fields.h" > > +#include <arpa/inet.h> > + > +#include <linux/if_arp.h> > +#ifdef HAVE_LINUX_IF_LINK_H > +# include <linux/if_link.h> > +#endif > +#include <linux/netdevice.h> > #include "netlink.h" > #include <linux/rtnetlink.h> > > #include "xlat/rtnl_link_attrs.h" > > +static int > +min_ifla_address_len(const unsigned short type) > +{ > + switch (type) { > + case ARPHRD_TUNNEL: > + case ARPHRD_SIT: > + case ARPHRD_IPGRE: > + return sizeof(struct in_addr); > + case ARPHRD_TUNNEL6: > + return sizeof(struct in6_addr); > + default: > + return 0; > + } > +} The same switch on ifi_type value is repeated twice: first in min_ifla_address_len, second in ifla_address_type_specific_decoder. In the previous version of this patch there was just one switch on ifi_type value. > + > +static bool > +ifla_address_default_decoder(struct tcb *const tcp, > + const kernel_ulong_t addr, > + const unsigned int len) > +{ > + const unsigned int addr_len = > + len < MAX_ADDR_LEN ? len : MAX_ADDR_LEN; > + size_t i; > + > + for (i = 0; i < addr_len; i++) { > + uint8_t buf; > + if (umove(tcp, addr + i, &buf) < 0) > + break; > + if (i) > + tprints(":"); > + tprintf("%02x", buf); > + } > + if (i < addr_len || addr_len < len) > + tprints(": ..."); > + > + return true; > +} ifla_address_default_decoder inefficiently fetches one byte at a time instead of the whole address. Why umoven_or_printaddr is not used here? > + > +static bool > +ifla_address_type_specific_decoder(const char *const buf, > + const unsigned short type) > +{ > + switch (type) { > + case ARPHRD_TUNNEL: > + case ARPHRD_SIT: > + case ARPHRD_IPGRE: { > + char str[INET_ADDRSTRLEN]; > + > + if (!inet_ntop(AF_INET, buf, str, sizeof(str))) > + return false; > + tprintf("%s", str); > + break; > + } > + case ARPHRD_TUNNEL6: { > + char str[INET6_ADDRSTRLEN]; > + > + if (!inet_ntop(AF_INET6, buf, str, sizeof(str))) > + return false; > + tprintf("%s", str); > + break; > + } > + default: > + return false; > + } > + > + return true; > +} > + > +static bool > +decode_ifla_address(struct tcb *const tcp, > + const kernel_ulong_t addr, > + const unsigned int len, > + const void *const opaque_data) > +{ > + const unsigned short type = > + ((struct ifinfomsg *) opaque_data)->ifi_type; > + size_t size = min_ifla_address_len(type); > + char buf[256]; > + > + if (!size || len < size) > + return ifla_address_default_decoder(tcp, addr, len); > + else if (!umoven_or_printaddr(tcp, addr, size, buf)) > + return ifla_address_type_specific_decoder(buf, type); > + > + return true; > +} > + > +static bool > +decode_rtnl_link_stats(struct tcb *const tcp, > + const kernel_ulong_t addr, > + const unsigned int len, > + const void *const opaque_data) > +{ > + struct rtnl_link_stats st; > + > + if (len < sizeof(st)) > + return false; The kernel may not transfer struct rtnl_link_stats.rx_nohandler despite the latter being defined by linux/if_link.h, e.g. if the kernel uses an older version of struct rtnl_link_stats. The minimal size is therefore not sizeof(struct rtnl_link_stats) but offsetofend(struct rtnl_link_stats, tx_compressed). Likewise, with struct rtnl_link_stats64.rx_nohandler. > + else if (!umove_or_printaddr(tcp, addr, &st)) { > + PRINT_FIELD_U("{", st, rx_packets); > + PRINT_FIELD_U(", ", st, tx_packets); > + PRINT_FIELD_U(", ", st, rx_bytes); > + PRINT_FIELD_U(", ", st, tx_bytes); > + PRINT_FIELD_U(", ", st, rx_errors); > + PRINT_FIELD_U(", ", st, tx_errors); > + PRINT_FIELD_U(", ", st, rx_dropped); > + PRINT_FIELD_U(", ", st, tx_dropped); > + PRINT_FIELD_U(", ", st, multicast); > + PRINT_FIELD_U(", ", st, collisions); > + > + PRINT_FIELD_U(", ", st, rx_length_errors); > + PRINT_FIELD_U(", ", st, rx_over_errors); > + PRINT_FIELD_U(", ", st, rx_crc_errors); > + PRINT_FIELD_U(", ", st, rx_frame_errors); > + PRINT_FIELD_U(", ", st, rx_fifo_errors); > + PRINT_FIELD_U(", ", st, rx_missed_errors); > + > + PRINT_FIELD_U(", ", st, tx_aborted_errors); > + PRINT_FIELD_U(", ", st, tx_carrier_errors); > + PRINT_FIELD_U(", ", st, tx_fifo_errors); > + PRINT_FIELD_U(", ", st, tx_heartbeat_errors); > + PRINT_FIELD_U(", ", st, tx_window_errors); > + > + PRINT_FIELD_U(", ", st, rx_compressed); > + PRINT_FIELD_U(", ", st, tx_compressed); > +#ifdef HAVE_STRUCT_RTNL_LINK_STATS_RX_NOHANDLER > + PRINT_FIELD_U(", ", st, rx_nohandler); > +#endif > + tprints("}"); > + } > + > + return true; > +} > + > +static bool > +decode_rtnl_link_ifmap(struct tcb *const tcp, > + const kernel_ulong_t addr, > + const unsigned int len, > + const void *const opaque_data) > +{ > + struct rtnl_link_ifmap map; > + const unsigned int sizeof_ifmap = > + offsetofend(struct rtnl_link_ifmap, port); > + > + if (len < sizeof_ifmap) > + return false; > + else if (!umoven_or_printaddr(tcp, addr, sizeof_ifmap, &map)) { > + PRINT_FIELD_X("{", map, mem_start); > + PRINT_FIELD_X(", ", map, mem_end); > + PRINT_FIELD_X(", ", map, base_addr); > + PRINT_FIELD_U(", ", map, irq); > + PRINT_FIELD_U(", ", map, dma); > + PRINT_FIELD_U(", ", map, port); > + tprints("}"); > + } > + > + return true; > +} > + > +static bool > +decode_rtnl_link_stats64(struct tcb *const tcp, > + const kernel_ulong_t addr, > + const unsigned int len, > + const void *const opaque_data) > +{ > +#ifdef HAVE_STRUCT_RTNL_LINK_STATS64 > + struct rtnl_link_stats64 st; > + > + if (len < sizeof(st)) > + return false; > + else if (!umove_or_printaddr(tcp, addr, &st)) { > + PRINT_FIELD_U("{", st, rx_packets); > + PRINT_FIELD_U(", ", st, tx_packets); > + PRINT_FIELD_U(", ", st, rx_bytes); > + PRINT_FIELD_U(", ", st, tx_bytes); > + PRINT_FIELD_U(", ", st, rx_errors); > + PRINT_FIELD_U(", ", st, tx_errors); > + PRINT_FIELD_U(", ", st, rx_dropped); > + PRINT_FIELD_U(", ", st, tx_dropped); > + PRINT_FIELD_U(", ", st, multicast); > + PRINT_FIELD_U(", ", st, collisions); > + > + PRINT_FIELD_U(", ", st, rx_length_errors); > + PRINT_FIELD_U(", ", st, rx_over_errors); > + PRINT_FIELD_U(", ", st, rx_crc_errors); > + PRINT_FIELD_U(", ", st, rx_frame_errors); > + PRINT_FIELD_U(", ", st, rx_fifo_errors); > + PRINT_FIELD_U(", ", st, rx_missed_errors); > + > + PRINT_FIELD_U(", ", st, tx_aborted_errors); > + PRINT_FIELD_U(", ", st, tx_carrier_errors); > + PRINT_FIELD_U(", ", st, tx_fifo_errors); > + PRINT_FIELD_U(", ", st, tx_heartbeat_errors); > + PRINT_FIELD_U(", ", st, tx_window_errors); > + > + PRINT_FIELD_U(", ", st, rx_compressed); > + PRINT_FIELD_U(", ", st, tx_compressed); > +#ifdef HAVE_STRUCT_RTNL_LINK_STATS64_RX_NOHANDLER > + PRINT_FIELD_U(", ", st, rx_nohandler); > +#endif > + tprints("}"); > + } > + > + return true; > +#else > + return false; > +#endif > +} > + > +static bool > +print_item_id(struct tcb *const tcp, void *const elem_buf, > + const size_t elem_size, void *const opaque_data) > +{ > + unsigned int *const count = opaque_data; > + > + /* MAX_PHYS_ITEM_ID_LEN = 32 */ > + if ((*count)++ >= 32) { > + tprints("..."); > + return false; > + } > + > + tprintf("%" PRIu8, *(uint8_t *) elem_buf); > + > + return true; > +} > + > +static bool > +decode_ifla_phys_item_id(struct tcb *const tcp, > + const kernel_ulong_t addr, > + const unsigned int len, > + const void *const opaque_data) > +{ > + uint8_t id; > + unsigned int count = 0; > + > + print_array(tcp, addr, len, &id, sizeof(id), > + umoven_or_printaddr, print_item_id, &count); I'm not sure it's the best way to decode struct netdev_phys_item_id.id. > + > + return true; > +} > + > +static const nla_decoder_t ifinfomsg_nla_decoders[] = { > + [IFLA_ADDRESS] = decode_ifla_address, > + [IFLA_BROADCAST] = decode_ifla_address, > + [IFLA_IFNAME] = decode_nla_str, > + [IFLA_MTU] = decode_nla_u32, > + [IFLA_LINK] = decode_nla_u32, > + [IFLA_QDISC] = decode_nla_str, > + [IFLA_STATS] = decode_rtnl_link_stats, > + [IFLA_COST] = NULL, > + [IFLA_PRIORITY] = NULL, > + [IFLA_MASTER] = decode_nla_u32, > + [IFLA_WIRELESS] = NULL, Here a parser of struct iw_event is expected. > + [IFLA_PROTINFO] = NULL, This one seems to be used in the kernel. > + [IFLA_TXQLEN] = decode_nla_u32, > + [IFLA_MAP] = decode_rtnl_link_ifmap, > + [IFLA_WEIGHT] = decode_nla_u32, > + [IFLA_OPERSTATE] = decode_nla_u8, > + [IFLA_LINKMODE] = decode_nla_u8, > + [IFLA_LINKINFO] = NULL, This one also seems to be used in the kernel. > + [IFLA_NET_NS_PID] = decode_nla_u32, > + [IFLA_IFALIAS] = decode_nla_str, > + [IFLA_NUM_VF] = decode_nla_u32, > + [IFLA_VFINFO_LIST] = NULL, Likewise. > + [IFLA_STATS64] = decode_rtnl_link_stats64, > + [IFLA_VF_PORTS] = NULL, Likewise. > + [IFLA_PORT_SELF] = NULL, Likewise. > + [IFLA_AF_SPEC] = NULL, Likewise. > + [IFLA_GROUP] = decode_nla_u32, > + [IFLA_NET_NS_FD] = decode_nla_u32, > + [IFLA_EXT_MASK] = decode_nla_u32, > + [IFLA_PROMISCUITY] = decode_nla_u32, > + [IFLA_NUM_TX_QUEUES] = decode_nla_u32, > + [IFLA_NUM_RX_QUEUES] = decode_nla_u32, > + [IFLA_CARRIER] = decode_nla_u8, > + [IFLA_PHYS_PORT_ID] = decode_ifla_phys_item_id, > + [IFLA_CARRIER_CHANGES] = decode_nla_u32, > + [IFLA_PHYS_SWITCH_ID] = decode_ifla_phys_item_id, > + [IFLA_LINK_NETNSID] = decode_nla_s32, > + [IFLA_PHYS_PORT_NAME] = decode_nla_str, > + [IFLA_PROTO_DOWN] = decode_nla_u8, > + [IFLA_GSO_MAX_SEGS] = decode_nla_u32, > + [IFLA_GSO_MAX_SIZE] = decode_nla_u32, > + [IFLA_PAD] = NULL, > + [IFLA_XDP] = NULL, Likewise. -- ldv
signature.asc
Description: PGP signature
------------------------------------------------------------------------------ Check out the vibrant tech community on one of the world's most engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________ Strace-devel mailing list Strace-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/strace-devel