ip-link: add switch to show human readable output

Byte and packet count can increase to really big numbers. This adds a
switch to show human readable output.

4: wl: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP mode DORMANT group default qlen 1000
    link/ether 00🇩🇪ad:be:ee:ef brd ff:ff:ff:ff:ff:ff
    RX: bytes  packets  errors  dropped overrun mcast
    1523846973 3969051  0       0       0       0
    TX: bytes  packets  errors  dropped carrier collsns
    8710088361 6077735  0       0       0       0
4: wl: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP mode DORMANT group default qlen 1000
    link/ether 00🇩🇪ad:be:ee:ef brd ff:ff:ff:ff:ff:ff
    RX: bytes  packets  errors  dropped overrun mcast
    1.5G       3.9M     0       0       0       0
    TX: bytes  packets  errors  dropped carrier collsns
    8.7G       6.0M     0       0       0       0
This commit is contained in:
Christian Hesse 2014-10-31 22:33:13 +01:00 committed by Stephen Hemminger
parent a0638e18b2
commit b68d983754
4 changed files with 233 additions and 66 deletions

View File

@ -11,6 +11,7 @@
#include "rtm_map.h" #include "rtm_map.h"
extern int preferred_family; extern int preferred_family;
extern int human_readable;
extern int show_stats; extern int show_stats;
extern int show_details; extern int show_details;
extern int show_raw; extern int show_raw;

View File

@ -24,6 +24,7 @@
#include "ip_common.h" #include "ip_common.h"
int preferred_family = AF_UNSPEC; int preferred_family = AF_UNSPEC;
int human_readable = 0;
int show_stats = 0; int show_stats = 0;
int show_details = 0; int show_details = 0;
int resolve_hosts = 0; int resolve_hosts = 0;
@ -47,6 +48,7 @@ static void usage(void)
" tunnel | tuntap | maddr | mroute | mrule | monitor | xfrm |\n" " tunnel | tuntap | maddr | mroute | mrule | monitor | xfrm |\n"
" netns | l2tp | tcp_metrics | token | netconf }\n" " netns | l2tp | tcp_metrics | token | netconf }\n"
" OPTIONS := { -V[ersion] | -s[tatistics] | -d[etails] | -r[esolve] |\n" " OPTIONS := { -V[ersion] | -s[tatistics] | -d[etails] | -r[esolve] |\n"
" -h[uman-readable] |\n"
" -f[amily] { inet | inet6 | ipx | dnet | bridge | link } |\n" " -f[amily] { inet | inet6 | ipx | dnet | bridge | link } |\n"
" -4 | -6 | -I | -D | -B | -0 |\n" " -4 | -6 | -I | -D | -B | -0 |\n"
" -l[oops] { maximum-addr-flush-attempts } |\n" " -l[oops] { maximum-addr-flush-attempts } |\n"
@ -212,6 +214,9 @@ int main(int argc, char **argv)
preferred_family = AF_DECnet; preferred_family = AF_DECnet;
} else if (strcmp(opt, "-B") == 0) { } else if (strcmp(opt, "-B") == 0) {
preferred_family = AF_BRIDGE; preferred_family = AF_BRIDGE;
} else if (matches(opt, "-human") == 0 ||
matches(opt, "-human-readable") == 0) {
++human_readable;
} else if (matches(opt, "-stats") == 0 || } else if (matches(opt, "-stats") == 0 ||
matches(opt, "-statistics") == 0) { matches(opt, "-statistics") == 0) {
++show_stats; ++show_stats;

View File

@ -319,107 +319,261 @@ static void print_vfinfo(FILE *fp, struct rtattr *vfinfo)
} }
} }
static void print_human64(FILE *fp, int length, uint64_t count)
{
char * prefix = "kMGTPE";
int written = 0, i;
uint64_t powi = 1;
if (count < 1000) {
/* we are below 1000, so no precision and no prefix */
written = fprintf(fp, "%"PRIu64, count);
} else {
/* increase value by a factor of 1000 and print
* if result is something a human can read */
for (i = 0; i < 6; i++) {
powi *= 1000;
if (count / 1000 < powi) {
written = fprintf(fp, "%"PRIu64".%"PRIu64"%c",
count / powi, count * 10 / powi % 10, *prefix);
break;
}
prefix++;
}
}
do {
fputc(' ', fp);
} while (written++ < length);
}
static void print_human32(FILE *fp, int length, uint32_t count)
{
char * prefix = "KMG";
int written = 0, i;
uint32_t powi = 1;
if (count < 1000) {
/* we are below 1000, so no precision and no prefix */
written = fprintf(fp, "%u", count);
} else {
/* increase value by a factor of 1000 and print
* if result is something a human can read */
for (i = 0; i < 3; i++) {
powi *= 1000;
if (count / 1000 < powi) {
written = fprintf(fp, "%u.%u%c",
count / powi, count * 10 / powi % 10, *prefix);
break;
}
prefix++;
}
}
do {
fputc(' ', fp);
} while (written++ < length);
}
static void print_link_stats64(FILE *fp, const struct rtnl_link_stats64 *s, static void print_link_stats64(FILE *fp, const struct rtnl_link_stats64 *s,
const struct rtattr *carrier_changes) const struct rtattr *carrier_changes)
{ {
/* RX stats */
fprintf(fp, " RX: bytes packets errors dropped overrun mcast %s%s", fprintf(fp, " RX: bytes packets errors dropped overrun mcast %s%s",
s->rx_compressed ? "compressed" : "", _SL_); s->rx_compressed ? "compressed" : "", _SL_);
fprintf(fp, " %-10"PRIu64" %-8"PRIu64" %-7"PRIu64" %-7"PRIu64" %-7"PRIu64" %-7"PRIu64"", if (human_readable) {
(uint64_t)s->rx_bytes, fprintf(fp, " ");
(uint64_t)s->rx_packets, print_human64(fp, 10, (uint64_t)s->rx_bytes);
(uint64_t)s->rx_errors, print_human64(fp, 8, (uint64_t)s->rx_packets);
(uint64_t)s->rx_dropped, print_human64(fp, 7, (uint64_t)s->rx_errors);
(uint64_t)s->rx_over_errors, print_human64(fp, 7, (uint64_t)s->rx_dropped);
(uint64_t)s->multicast); print_human64(fp, 7, (uint64_t)s->rx_over_errors);
if (s->rx_compressed) print_human64(fp, 7, (uint64_t)s->multicast);
fprintf(fp, " %-7"PRIu64"", if (s->rx_compressed)
(uint64_t)s->rx_compressed); print_human64(fp, 7, (uint64_t)s->rx_compressed);
} else {
fprintf(fp, " %-10"PRIu64" %-8"PRIu64" %-7"PRIu64" %-7"PRIu64" %-7"PRIu64" %-7"PRIu64"",
(uint64_t)s->rx_bytes,
(uint64_t)s->rx_packets,
(uint64_t)s->rx_errors,
(uint64_t)s->rx_dropped,
(uint64_t)s->rx_over_errors,
(uint64_t)s->multicast);
if (s->rx_compressed)
fprintf(fp, " %-7"PRIu64"",
(uint64_t)s->rx_compressed);
}
/* RX error stats */
if (show_stats > 1) { if (show_stats > 1) {
fprintf(fp, "%s", _SL_); fprintf(fp, "%s", _SL_);
fprintf(fp, " RX errors: length crc frame fifo missed%s", _SL_); fprintf(fp, " RX errors: length crc frame fifo missed%s", _SL_);
fprintf(fp, " %-7"PRIu64" %-7"PRIu64" %-7"PRIu64" %-7"PRIu64" %-7"PRIu64"", if (human_readable) {
(uint64_t)s->rx_length_errors, fprintf(fp, " ");
(uint64_t)s->rx_crc_errors, print_human64(fp, 8, (uint64_t)s->rx_length_errors);
(uint64_t)s->rx_frame_errors, print_human64(fp, 7, (uint64_t)s->rx_crc_errors);
(uint64_t)s->rx_fifo_errors, print_human64(fp, 7, (uint64_t)s->rx_frame_errors);
(uint64_t)s->rx_missed_errors); print_human64(fp, 7, (uint64_t)s->rx_fifo_errors);
print_human64(fp, 7, (uint64_t)s->rx_missed_errors);
} else {
fprintf(fp, " %-8"PRIu64" %-7"PRIu64" %-7"PRIu64" %-7"PRIu64" %-7"PRIu64"",
(uint64_t)s->rx_length_errors,
(uint64_t)s->rx_crc_errors,
(uint64_t)s->rx_frame_errors,
(uint64_t)s->rx_fifo_errors,
(uint64_t)s->rx_missed_errors);
}
} }
fprintf(fp, "%s", _SL_); fprintf(fp, "%s", _SL_);
/* TX stats */
fprintf(fp, " TX: bytes packets errors dropped carrier collsns %s%s", fprintf(fp, " TX: bytes packets errors dropped carrier collsns %s%s",
(uint64_t)s->tx_compressed ? "compressed" : "", _SL_); (uint64_t)s->tx_compressed ? "compressed" : "", _SL_);
fprintf(fp, " %-10"PRIu64" %-8"PRIu64" %-7"PRIu64" %-7"PRIu64" %-7"PRIu64" %-7"PRIu64"", if (human_readable) {
(uint64_t)s->tx_bytes, fprintf(fp, " ");
(uint64_t)s->tx_packets, print_human64(fp, 10, (uint64_t)s->tx_bytes);
(uint64_t)s->tx_errors, print_human64(fp, 8, (uint64_t)s->tx_packets);
(uint64_t)s->tx_dropped, print_human64(fp, 7, (uint64_t)s->tx_errors);
(uint64_t)s->tx_carrier_errors, print_human64(fp, 7, (uint64_t)s->tx_dropped);
(uint64_t)s->collisions); print_human64(fp, 7, (uint64_t)s->tx_carrier_errors);
if (s->tx_compressed) print_human64(fp, 7, (uint64_t)s->collisions);
fprintf(fp, " %-7"PRIu64"", if (s->tx_compressed)
(uint64_t)s->tx_compressed); print_human64(fp, 7, (uint64_t)s->tx_compressed);
} else {
fprintf(fp, " %-10"PRIu64" %-8"PRIu64" %-7"PRIu64" %-7"PRIu64" %-7"PRIu64" %-7"PRIu64"",
(uint64_t)s->tx_bytes,
(uint64_t)s->tx_packets,
(uint64_t)s->tx_errors,
(uint64_t)s->tx_dropped,
(uint64_t)s->tx_carrier_errors,
(uint64_t)s->collisions);
if (s->tx_compressed)
fprintf(fp, " %-7"PRIu64"",
(uint64_t)s->tx_compressed);
}
/* TX error stats */
if (show_stats > 1) { if (show_stats > 1) {
fprintf(fp, "%s", _SL_); fprintf(fp, "%s", _SL_);
fprintf(fp, " TX errors: aborted fifo window heartbeat"); fprintf(fp, " TX errors: aborted fifo window heartbeat");
if (carrier_changes) if (carrier_changes)
fprintf(fp, " transns"); fprintf(fp, " transns");
fprintf(fp, "%s", _SL_); fprintf(fp, "%s", _SL_);
fprintf(fp, " %-7"PRIu64" %-7"PRIu64" %-7"PRIu64" %-8"PRIu64"", if (human_readable) {
(uint64_t)s->tx_aborted_errors, fprintf(fp, " ");
(uint64_t)s->tx_fifo_errors, print_human64(fp, 8, (uint64_t)s->tx_aborted_errors);
(uint64_t)s->tx_window_errors, print_human64(fp, 7, (uint64_t)s->tx_fifo_errors);
(uint64_t)s->tx_heartbeat_errors); print_human64(fp, 7, (uint64_t)s->tx_window_errors);
if (carrier_changes) print_human64(fp, 7, (uint64_t)s->tx_heartbeat_errors);
fprintf(fp, " %-7u", if (carrier_changes)
*(uint32_t*)RTA_DATA(carrier_changes)); print_human64(fp, 7, (uint64_t)*(uint32_t*)RTA_DATA(carrier_changes));
} else {
fprintf(fp, " %-8"PRIu64" %-7"PRIu64" %-7"PRIu64" %-7"PRIu64"",
(uint64_t)s->tx_aborted_errors,
(uint64_t)s->tx_fifo_errors,
(uint64_t)s->tx_window_errors,
(uint64_t)s->tx_heartbeat_errors);
if (carrier_changes)
fprintf(fp, " %-7u",
*(uint32_t*)RTA_DATA(carrier_changes));
}
} }
} }
static void print_link_stats32(FILE *fp, const struct rtnl_link_stats *s, static void print_link_stats32(FILE *fp, const struct rtnl_link_stats *s,
const struct rtattr *carrier_changes) const struct rtattr *carrier_changes)
{ {
/* RX stats */
fprintf(fp, " RX: bytes packets errors dropped overrun mcast %s%s", fprintf(fp, " RX: bytes packets errors dropped overrun mcast %s%s",
s->rx_compressed ? "compressed" : "", _SL_); s->rx_compressed ? "compressed" : "", _SL_);
fprintf(fp, " %-10u %-8u %-7u %-7u %-7u %-7u", if (human_readable) {
s->rx_bytes, s->rx_packets, s->rx_errors, fprintf(fp, " ");
s->rx_dropped, s->rx_over_errors, print_human32(fp, 10, s->rx_bytes);
s->multicast print_human32(fp, 8, s->rx_packets);
); print_human32(fp, 7, s->rx_errors);
if (s->rx_compressed) print_human32(fp, 7, s->rx_dropped);
fprintf(fp, " %-7u", s->rx_compressed); print_human32(fp, 7, s->rx_over_errors);
print_human32(fp, 7, s->multicast);
if (s->rx_compressed)
print_human32(fp, 7, s->rx_compressed);
} else {
fprintf(fp, " %-10u %-8u %-7u %-7u %-7u %-7u",
s->rx_bytes, s->rx_packets, s->rx_errors,
s->rx_dropped, s->rx_over_errors,
s->multicast);
if (s->rx_compressed)
fprintf(fp, " %-7u", s->rx_compressed);
}
/* RX error stats */
if (show_stats > 1) { if (show_stats > 1) {
fprintf(fp, "%s", _SL_); fprintf(fp, "%s", _SL_);
fprintf(fp, " RX errors: length crc frame fifo missed%s", _SL_); fprintf(fp, " RX errors: length crc frame fifo missed%s", _SL_);
fprintf(fp, " %-7u %-7u %-7u %-7u %-7u", if (human_readable) {
s->rx_length_errors, fprintf(fp, " ");
s->rx_crc_errors, print_human32(fp, 8, s->rx_length_errors);
s->rx_frame_errors, print_human32(fp, 7, s->rx_crc_errors);
s->rx_fifo_errors, print_human32(fp, 7, s->rx_frame_errors);
s->rx_missed_errors print_human32(fp, 7, s->rx_fifo_errors);
); print_human32(fp, 7, s->rx_missed_errors);
} else {
fprintf(fp, " %-8u %-7u %-7u %-7u %-7u",
s->rx_length_errors,
s->rx_crc_errors,
s->rx_frame_errors,
s->rx_fifo_errors,
s->rx_missed_errors);
}
} }
fprintf(fp, "%s", _SL_); fprintf(fp, "%s", _SL_);
/* TX stats */
fprintf(fp, " TX: bytes packets errors dropped carrier collsns %s%s", fprintf(fp, " TX: bytes packets errors dropped carrier collsns %s%s",
s->tx_compressed ? "compressed" : "", _SL_); s->tx_compressed ? "compressed" : "", _SL_);
fprintf(fp, " %-10u %-8u %-7u %-7u %-7u %-7u", if (human_readable) {
s->tx_bytes, s->tx_packets, s->tx_errors, fprintf(fp, " ");
s->tx_dropped, s->tx_carrier_errors, s->collisions); print_human32(fp, 10, s->tx_bytes);
if (s->tx_compressed) print_human32(fp, 8, s->tx_packets);
fprintf(fp, " %-7u", s->tx_compressed); print_human32(fp, 7, s->tx_errors);
print_human32(fp, 7, s->tx_dropped);
print_human32(fp, 7, s->tx_carrier_errors);
print_human32(fp, 7, s->collisions);
if (s->tx_compressed)
print_human32(fp, 7, s->tx_compressed);
} else {
fprintf(fp, " %-10u %-8u %-7u %-7u %-7u %-7u",
s->tx_bytes, s->tx_packets, s->tx_errors,
s->tx_dropped, s->tx_carrier_errors, s->collisions);
if (s->tx_compressed)
fprintf(fp, " %-7u", s->tx_compressed);
}
/* TX error stats */
if (show_stats > 1) { if (show_stats > 1) {
fprintf(fp, "%s", _SL_); fprintf(fp, "%s", _SL_);
fprintf(fp, " TX errors: aborted fifo window heartbeat"); fprintf(fp, " TX errors: aborted fifo window heartbeat");
if (carrier_changes) if (carrier_changes)
fprintf(fp, " transns"); fprintf(fp, " transns");
fprintf(fp, "%s", _SL_); fprintf(fp, "%s", _SL_);
fprintf(fp, " %-7u %-7u %-7u %-8u", if (human_readable) {
s->tx_aborted_errors, fprintf(fp, " ");
s->tx_fifo_errors, print_human32(fp, 8, s->tx_aborted_errors);
s->tx_window_errors, print_human32(fp, 7, s->tx_fifo_errors);
s->tx_heartbeat_errors print_human32(fp, 7, s->tx_window_errors);
); print_human32(fp, 7, s->tx_heartbeat_errors);
if (carrier_changes) if (carrier_changes)
fprintf(fp, " %-7u", print_human32(fp, 7, *(uint32_t*)RTA_DATA(carrier_changes));
*(uint32_t*)RTA_DATA(carrier_changes)); } else {
fprintf(fp, " %-8u %-7u %-7u %-7u",
s->tx_aborted_errors,
s->tx_fifo_errors,
s->tx_window_errors,
s->tx_heartbeat_errors);
if (carrier_changes)
fprintf(fp, " %-7u",
*(uint32_t*)RTA_DATA(carrier_changes));
}
} }
} }

View File

@ -16,6 +16,7 @@ ip-link \- network device configuration
.ti -8 .ti -8
.IR OPTIONS " := { " .IR OPTIONS " := { "
\fB\-V\fR[\fIersion\fR] | \fB\-V\fR[\fIersion\fR] |
\fB\-h\fR[\fIuman-readable\fR] |
\fB\-s\fR[\fItatistics\fR] | \fB\-s\fR[\fItatistics\fR] |
\fB\-r\fR[\fIesolve\fR] | \fB\-r\fR[\fIesolve\fR] |
\fB\-f\fR[\fIamily\fR] { \fB\-f\fR[\fIamily\fR] {
@ -660,6 +661,12 @@ specifies what group of devices to show.
.B up .B up
only display running interfaces. only display running interfaces.
.SH "NOTES"
Human readable values are calculated with SI prefixes, so with a decimal
base, not binary. (This is unlike
.BR ifconfig (8)
, with uses binary prefix.) 1,000 bytes are 1 kB, 1,000 kB are 1 MB, ...
.SH "EXAMPLES" .SH "EXAMPLES"
.PP .PP
ip link show ip link show