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

Attachment: 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

Reply via email to