[PATCH v2 1/2] rtnl_link: decode ifinfomsg netlink attributes

JingPiao Chen chenjingpiao at gmail.com
Sat Aug 19 01:50:10 UTC 2017


* 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.
(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;
+	}
+}
+
+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;
+}
+
+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;
+	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);
+
+	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,
+	[IFLA_PROTINFO]		= NULL,
+	[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,
+	[IFLA_NET_NS_PID]	= decode_nla_u32,
+	[IFLA_IFALIAS]		= decode_nla_str,
+	[IFLA_NUM_VF]		= decode_nla_u32,
+	[IFLA_VFINFO_LIST]	= NULL,
+	[IFLA_STATS64]		= decode_rtnl_link_stats64,
+	[IFLA_VF_PORTS]		= NULL,
+	[IFLA_PORT_SELF]	= NULL,
+	[IFLA_AF_SPEC]		= NULL,
+	[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,
+	[IFLA_EVENT]		= decode_nla_u32
+};
+
 DECL_NETLINK_ROUTE_DECODER(decode_ifinfomsg)
 {
 	struct ifinfomsg ifinfo = { .ifi_family = family };
@@ -66,6 +360,8 @@ DECL_NETLINK_ROUTE_DECODER(decode_ifinfomsg)
 	if (decode_nla && len > offset) {
 		tprints(", ");
 		decode_nlattr(tcp, addr + offset, len - offset,
-			      rtnl_link_attrs, "IFLA_???", NULL, 0, NULL);
+			      rtnl_link_attrs, "IFLA_???",
+			      ifinfomsg_nla_decoders,
+			      ARRAY_SIZE(ifinfomsg_nla_decoders), &ifinfo);
 	}
 }
-- 
2.7.4





More information about the Strace-devel mailing list