ip: Introduce get_rtnl_link_stats_rta() to get link statistics

Assume all statistics in ip(8) represented either by IFLA_STATS64 or
IFLA_STATS is 64 bit. It is clean that we can store __u32 counters of
@struct rtnl_link_stats in __u64 counters in @struct rtnl_link_stats64.

New get_rtnl_link_stats_rta() follows __print_link_stats() behaviour on
handling of stats attribute: copy no more than size of data structure
and no less than attribute length zeroing rest.

Drop print_link_stats32() as it's functionality can be handled by 64bit
variant. Move code from __print_link_stats() to print_link_stats64() and
finally rename print_link_stats64() to __print_link_stats().

More users of introduced function will come in future.

Signed-off-by: Serhey Popovych <serhe.popovych@gmail.com>
Signed-off-by: David Ahern <dsahern@gmail.com>
This commit is contained in:
Serhey Popovych 2018-02-07 08:30:52 +02:00 committed by David Ahern
parent fb7b816827
commit 9a7bd5442b
3 changed files with 186 additions and 293 deletions

View File

@ -284,6 +284,9 @@ int make_path(const char *path, mode_t mode);
char *find_cgroup2_mount(void); char *find_cgroup2_mount(void);
int get_command_name(const char *pid, char *comm, size_t len); int get_command_name(const char *pid, char *comm, size_t len);
int get_rtnl_link_stats_rta(struct rtnl_link_stats64 *stats64,
struct rtattr *tb[]);
#ifdef NEED_STRLCPY #ifdef NEED_STRLCPY
size_t strlcpy(char *dst, const char *src, size_t size); size_t strlcpy(char *dst, const char *src, size_t size);
size_t strlcat(char *dst, const char *src, size_t size); size_t strlcat(char *dst, const char *src, size_t size);

View File

@ -593,306 +593,151 @@ static void print_vf_stats64(FILE *fp, struct rtattr *vfstats)
} }
} }
static void print_link_stats64(FILE *fp, const struct rtnl_link_stats64 *s, static void __print_link_stats(FILE *fp, struct rtattr *tb[])
const struct rtattr *carrier_changes)
{
if (is_json_context()) {
open_json_object("stats64");
/* RX stats */
open_json_object("rx");
print_uint(PRINT_JSON, "bytes", NULL, s->rx_bytes);
print_uint(PRINT_JSON, "packets", NULL, s->rx_packets);
print_uint(PRINT_JSON, "errors", NULL, s->rx_errors);
print_uint(PRINT_JSON, "dropped", NULL, s->rx_dropped);
print_uint(PRINT_JSON, "over_errors", NULL, s->rx_over_errors);
print_uint(PRINT_JSON, "multicast", NULL, s->multicast);
if (s->rx_compressed)
print_uint(PRINT_JSON,
"compressed", NULL, s->rx_compressed);
/* RX error stats */
if (show_stats > 1) {
print_uint(PRINT_JSON,
"length_errors",
NULL, s->rx_length_errors);
print_uint(PRINT_JSON,
"crc_errors",
NULL, s->rx_crc_errors);
print_uint(PRINT_JSON,
"frame_errors",
NULL, s->rx_frame_errors);
print_uint(PRINT_JSON,
"fifo_errors",
NULL, s->rx_fifo_errors);
print_uint(PRINT_JSON,
"missed_errors",
NULL, s->rx_missed_errors);
if (s->rx_nohandler)
print_uint(PRINT_JSON,
"nohandler", NULL, s->rx_nohandler);
}
close_json_object();
/* TX stats */
open_json_object("tx");
print_uint(PRINT_JSON, "bytes", NULL, s->tx_bytes);
print_uint(PRINT_JSON, "packets", NULL, s->tx_packets);
print_uint(PRINT_JSON, "errors", NULL, s->tx_errors);
print_uint(PRINT_JSON, "dropped", NULL, s->tx_dropped);
print_uint(PRINT_JSON,
"carrier_errors",
NULL, s->tx_carrier_errors);
print_uint(PRINT_JSON, "collisions", NULL, s->collisions);
if (s->tx_compressed)
print_uint(PRINT_JSON,
"compressed", NULL, s->tx_compressed);
/* TX error stats */
if (show_stats > 1) {
print_uint(PRINT_JSON,
"aborted_errors",
NULL, s->tx_aborted_errors);
print_uint(PRINT_JSON,
"fifo_errors",
NULL, s->tx_fifo_errors);
print_uint(PRINT_JSON,
"window_errors",
NULL, s->tx_window_errors);
print_uint(PRINT_JSON,
"heartbeat_errors",
NULL, s->tx_heartbeat_errors);
if (carrier_changes)
print_uint(PRINT_JSON, "carrier_changes", NULL,
rta_getattr_u32(carrier_changes));
}
close_json_object();
close_json_object();
} else {
/* RX stats */
fprintf(fp, " RX: bytes packets errors dropped overrun mcast %s%s",
s->rx_compressed ? "compressed" : "", _SL_);
fprintf(fp, " ");
print_num(fp, 10, s->rx_bytes);
print_num(fp, 8, s->rx_packets);
print_num(fp, 7, s->rx_errors);
print_num(fp, 7, s->rx_dropped);
print_num(fp, 7, s->rx_over_errors);
print_num(fp, 7, s->multicast);
if (s->rx_compressed)
print_num(fp, 7, s->rx_compressed);
/* RX error stats */
if (show_stats > 1) {
fprintf(fp, "%s", _SL_);
fprintf(fp, " RX errors: length crc frame fifo missed%s%s",
s->rx_nohandler ? " nohandler" : "", _SL_);
fprintf(fp, " ");
print_num(fp, 8, s->rx_length_errors);
print_num(fp, 7, s->rx_crc_errors);
print_num(fp, 7, s->rx_frame_errors);
print_num(fp, 7, s->rx_fifo_errors);
print_num(fp, 7, s->rx_missed_errors);
if (s->rx_nohandler)
print_num(fp, 7, s->rx_nohandler);
}
fprintf(fp, "%s", _SL_);
/* TX stats */
fprintf(fp, " TX: bytes packets errors dropped carrier collsns %s%s",
s->tx_compressed ? "compressed" : "", _SL_);
fprintf(fp, " ");
print_num(fp, 10, s->tx_bytes);
print_num(fp, 8, s->tx_packets);
print_num(fp, 7, s->tx_errors);
print_num(fp, 7, s->tx_dropped);
print_num(fp, 7, s->tx_carrier_errors);
print_num(fp, 7, s->collisions);
if (s->tx_compressed)
print_num(fp, 7, s->tx_compressed);
/* TX error stats */
if (show_stats > 1) {
fprintf(fp, "%s", _SL_);
fprintf(fp, " TX errors: aborted fifo window heartbeat");
if (carrier_changes)
fprintf(fp, " transns");
fprintf(fp, "%s", _SL_);
fprintf(fp, " ");
print_num(fp, 8, s->tx_aborted_errors);
print_num(fp, 7, s->tx_fifo_errors);
print_num(fp, 7, s->tx_window_errors);
print_num(fp, 7, s->tx_heartbeat_errors);
if (carrier_changes)
print_num(fp, 7,
rta_getattr_u32(carrier_changes));
}
}
}
static void print_link_stats32(FILE *fp, const struct rtnl_link_stats *s,
const struct rtattr *carrier_changes)
{
if (is_json_context()) {
open_json_object("stats");
/* RX stats */
open_json_object("rx");
print_uint(PRINT_JSON, "bytes", NULL, s->rx_bytes);
print_uint(PRINT_JSON, "packets", NULL, s->rx_packets);
print_uint(PRINT_JSON, "errors", NULL, s->rx_errors);
print_uint(PRINT_JSON, "dropped", NULL, s->rx_dropped);
print_uint(PRINT_JSON, "over_errors", NULL, s->rx_over_errors);
print_uint(PRINT_JSON, "multicast", NULL, s->multicast);
if (s->rx_compressed)
print_uint(PRINT_JSON,
"compressed", NULL, s->rx_compressed);
/* RX error stats */
if (show_stats > 1) {
print_uint(PRINT_JSON,
"length_errors",
NULL, s->rx_length_errors);
print_uint(PRINT_JSON,
"crc_errors",
NULL, s->rx_crc_errors);
print_uint(PRINT_JSON,
"frame_errors",
NULL, s->rx_frame_errors);
print_uint(PRINT_JSON,
"fifo_errors",
NULL, s->rx_fifo_errors);
print_uint(PRINT_JSON,
"missed_errors",
NULL, s->rx_missed_errors);
if (s->rx_nohandler)
print_uint(PRINT_JSON,
"nohandler", NULL, s->rx_nohandler);
}
close_json_object();
/* TX stats */
open_json_object("tx");
print_uint(PRINT_JSON, "bytes", NULL, s->tx_bytes);
print_uint(PRINT_JSON, "packets", NULL, s->tx_packets);
print_uint(PRINT_JSON, "errors", NULL, s->tx_errors);
print_uint(PRINT_JSON, "dropped", NULL, s->tx_dropped);
print_uint(PRINT_JSON,
"carrier_errors",
NULL, s->tx_carrier_errors);
print_uint(PRINT_JSON, "collisions", NULL, s->collisions);
if (s->tx_compressed)
print_uint(PRINT_JSON,
"compressed", NULL, s->tx_compressed);
/* TX error stats */
if (show_stats > 1) {
print_uint(PRINT_JSON,
"aborted_errors",
NULL, s->tx_aborted_errors);
print_uint(PRINT_JSON,
"fifo_errors",
NULL, s->tx_fifo_errors);
print_uint(PRINT_JSON,
"window_errors",
NULL, s->tx_window_errors);
print_uint(PRINT_JSON,
"heartbeat_errors",
NULL, s->tx_heartbeat_errors);
if (carrier_changes)
print_uint(PRINT_JSON, "carrier_changes", NULL,
rta_getattr_u32(carrier_changes));
}
close_json_object();
close_json_object();
} else {
/* RX stats */
fprintf(fp, " RX: bytes packets errors dropped overrun mcast %s%s",
s->rx_compressed ? "compressed" : "", _SL_);
fprintf(fp, " ");
print_num(fp, 10, s->rx_bytes);
print_num(fp, 8, s->rx_packets);
print_num(fp, 7, s->rx_errors);
print_num(fp, 7, s->rx_dropped);
print_num(fp, 7, s->rx_over_errors);
print_num(fp, 7, s->multicast);
if (s->rx_compressed)
print_num(fp, 7, s->rx_compressed);
/* RX error stats */
if (show_stats > 1) {
fprintf(fp, "%s", _SL_);
fprintf(fp, " RX errors: length crc frame fifo missed%s%s",
s->rx_nohandler ? " nohandler" : "", _SL_);
fprintf(fp, " ");
print_num(fp, 8, s->rx_length_errors);
print_num(fp, 7, s->rx_crc_errors);
print_num(fp, 7, s->rx_frame_errors);
print_num(fp, 7, s->rx_fifo_errors);
print_num(fp, 7, s->rx_missed_errors);
if (s->rx_nohandler)
print_num(fp, 7, s->rx_nohandler);
}
fprintf(fp, "%s", _SL_);
/* TX stats */
fprintf(fp, " TX: bytes packets errors dropped carrier collsns %s%s",
s->tx_compressed ? "compressed" : "", _SL_);
fprintf(fp, " ");
print_num(fp, 10, s->tx_bytes);
print_num(fp, 8, s->tx_packets);
print_num(fp, 7, s->tx_errors);
print_num(fp, 7, s->tx_dropped);
print_num(fp, 7, s->tx_carrier_errors);
print_num(fp, 7, s->collisions);
if (s->tx_compressed)
print_num(fp, 7, s->tx_compressed);
/* TX error stats */
if (show_stats > 1) {
fprintf(fp, "%s", _SL_);
fprintf(fp, " TX errors: aborted fifo window heartbeat");
if (carrier_changes)
fprintf(fp, " transns");
fprintf(fp, "%s", _SL_);
fprintf(fp, " ");
print_num(fp, 8, s->tx_aborted_errors);
print_num(fp, 7, s->tx_fifo_errors);
print_num(fp, 7, s->tx_window_errors);
print_num(fp, 7, s->tx_heartbeat_errors);
if (carrier_changes)
print_num(fp, 7,
rta_getattr_u32(carrier_changes));
}
}
}
static void __print_link_stats(FILE *fp, struct rtattr **tb)
{ {
const struct rtattr *carrier_changes = tb[IFLA_CARRIER_CHANGES]; const struct rtattr *carrier_changes = tb[IFLA_CARRIER_CHANGES];
struct rtnl_link_stats64 _s, *s = &_s;
int ret;
if (tb[IFLA_STATS64]) { ret = get_rtnl_link_stats_rta(s, tb);
struct rtnl_link_stats64 stats = { 0 }; if (ret < 0)
return;
memcpy(&stats, RTA_DATA(tb[IFLA_STATS64]), if (is_json_context()) {
MIN(RTA_PAYLOAD(tb[IFLA_STATS64]), sizeof(stats))); open_json_object((ret == sizeof(*s)) ? "stats64" : "stats");
print_link_stats64(fp, &stats, carrier_changes); /* RX stats */
} else if (tb[IFLA_STATS]) { open_json_object("rx");
struct rtnl_link_stats stats = { 0 }; print_uint(PRINT_JSON, "bytes", NULL, s->rx_bytes);
print_uint(PRINT_JSON, "packets", NULL, s->rx_packets);
print_uint(PRINT_JSON, "errors", NULL, s->rx_errors);
print_uint(PRINT_JSON, "dropped", NULL, s->rx_dropped);
print_uint(PRINT_JSON, "over_errors", NULL, s->rx_over_errors);
print_uint(PRINT_JSON, "multicast", NULL, s->multicast);
if (s->rx_compressed)
print_uint(PRINT_JSON,
"compressed", NULL, s->rx_compressed);
memcpy(&stats, RTA_DATA(tb[IFLA_STATS]), /* RX error stats */
MIN(RTA_PAYLOAD(tb[IFLA_STATS]), sizeof(stats))); if (show_stats > 1) {
print_uint(PRINT_JSON,
"length_errors",
NULL, s->rx_length_errors);
print_uint(PRINT_JSON,
"crc_errors",
NULL, s->rx_crc_errors);
print_uint(PRINT_JSON,
"frame_errors",
NULL, s->rx_frame_errors);
print_uint(PRINT_JSON,
"fifo_errors",
NULL, s->rx_fifo_errors);
print_uint(PRINT_JSON,
"missed_errors",
NULL, s->rx_missed_errors);
if (s->rx_nohandler)
print_uint(PRINT_JSON,
"nohandler", NULL, s->rx_nohandler);
}
close_json_object();
print_link_stats32(fp, &stats, carrier_changes); /* TX stats */
open_json_object("tx");
print_uint(PRINT_JSON, "bytes", NULL, s->tx_bytes);
print_uint(PRINT_JSON, "packets", NULL, s->tx_packets);
print_uint(PRINT_JSON, "errors", NULL, s->tx_errors);
print_uint(PRINT_JSON, "dropped", NULL, s->tx_dropped);
print_uint(PRINT_JSON,
"carrier_errors",
NULL, s->tx_carrier_errors);
print_uint(PRINT_JSON, "collisions", NULL, s->collisions);
if (s->tx_compressed)
print_uint(PRINT_JSON,
"compressed", NULL, s->tx_compressed);
/* TX error stats */
if (show_stats > 1) {
print_uint(PRINT_JSON,
"aborted_errors",
NULL, s->tx_aborted_errors);
print_uint(PRINT_JSON,
"fifo_errors",
NULL, s->tx_fifo_errors);
print_uint(PRINT_JSON,
"window_errors",
NULL, s->tx_window_errors);
print_uint(PRINT_JSON,
"heartbeat_errors",
NULL, s->tx_heartbeat_errors);
if (carrier_changes)
print_uint(PRINT_JSON, "carrier_changes", NULL,
rta_getattr_u32(carrier_changes));
}
close_json_object();
close_json_object();
} else {
/* RX stats */
fprintf(fp, " RX: bytes packets errors dropped overrun mcast %s%s",
s->rx_compressed ? "compressed" : "", _SL_);
fprintf(fp, " ");
print_num(fp, 10, s->rx_bytes);
print_num(fp, 8, s->rx_packets);
print_num(fp, 7, s->rx_errors);
print_num(fp, 7, s->rx_dropped);
print_num(fp, 7, s->rx_over_errors);
print_num(fp, 7, s->multicast);
if (s->rx_compressed)
print_num(fp, 7, s->rx_compressed);
/* RX error stats */
if (show_stats > 1) {
fprintf(fp, "%s", _SL_);
fprintf(fp, " RX errors: length crc frame fifo missed%s%s",
s->rx_nohandler ? " nohandler" : "", _SL_);
fprintf(fp, " ");
print_num(fp, 8, s->rx_length_errors);
print_num(fp, 7, s->rx_crc_errors);
print_num(fp, 7, s->rx_frame_errors);
print_num(fp, 7, s->rx_fifo_errors);
print_num(fp, 7, s->rx_missed_errors);
if (s->rx_nohandler)
print_num(fp, 7, s->rx_nohandler);
}
fprintf(fp, "%s", _SL_);
/* TX stats */
fprintf(fp, " TX: bytes packets errors dropped carrier collsns %s%s",
s->tx_compressed ? "compressed" : "", _SL_);
fprintf(fp, " ");
print_num(fp, 10, s->tx_bytes);
print_num(fp, 8, s->tx_packets);
print_num(fp, 7, s->tx_errors);
print_num(fp, 7, s->tx_dropped);
print_num(fp, 7, s->tx_carrier_errors);
print_num(fp, 7, s->collisions);
if (s->tx_compressed)
print_num(fp, 7, s->tx_compressed);
/* TX error stats */
if (show_stats > 1) {
fprintf(fp, "%s", _SL_);
fprintf(fp, " TX errors: aborted fifo window heartbeat");
if (carrier_changes)
fprintf(fp, " transns");
fprintf(fp, "%s", _SL_);
fprintf(fp, " ");
print_num(fp, 8, s->tx_aborted_errors);
print_num(fp, 7, s->tx_fifo_errors);
print_num(fp, 7, s->tx_window_errors);
print_num(fp, 7, s->tx_heartbeat_errors);
if (carrier_changes)
print_num(fp, 7,
rta_getattr_u32(carrier_changes));
}
} }
} }

View File

@ -1431,6 +1431,51 @@ int get_real_family(int rtm_type, int rtm_family)
return rtm_family; return rtm_family;
} }
/* Based on copy_rtnl_link_stats() from kernel at net/core/rtnetlink.c */
static void copy_rtnl_link_stats64(struct rtnl_link_stats64 *stats64,
const struct rtnl_link_stats *stats)
{
__u64 *a = (__u64 *)stats64;
const __u32 *b = (const __u32 *)stats;
const __u32 *e = b + sizeof(*stats) / sizeof(*b);
while (b < e)
*a++ = *b++;
}
int get_rtnl_link_stats_rta(struct rtnl_link_stats64 *stats64,
struct rtattr *tb[])
{
struct rtnl_link_stats stats;
void *s;
struct rtattr *rta;
int size, len;
if (tb[IFLA_STATS64]) {
rta = tb[IFLA_STATS64];
size = sizeof(struct rtnl_link_stats64);
s = stats64;
} else if (tb[IFLA_STATS]) {
rta = tb[IFLA_STATS];
size = sizeof(struct rtnl_link_stats);
s = &stats;
} else {
return -1;
}
len = RTA_PAYLOAD(rta);
if (len < size)
memset(s + len, 0, size - len);
else
len = size;
memcpy(s, RTA_DATA(rta), len);
if (s != stats64)
copy_rtnl_link_stats64(stats64, s);
return size;
}
#ifdef NEED_STRLCPY #ifdef NEED_STRLCPY
size_t strlcpy(char *dst, const char *src, size_t size) size_t strlcpy(char *dst, const char *src, size_t size)
{ {