summaryrefslogtreecommitdiffstats
path: root/src/network/networkctl.c
diff options
context:
space:
mode:
authorYu Watanabe <watanabe.yu+github@gmail.com>2019-05-24 17:37:48 +0200
committerYu Watanabe <watanabe.yu+github@gmail.com>2019-06-01 03:24:47 +0200
commita459b24f7e4d9030135e4ea40575d42f4a8fffdf (patch)
tree2421410e9a69b1932fc26dda83bf3312461ac04b /src/network/networkctl.c
parentnetlink: set attribute size of IFLA_STATS and IFLA_STATS64 (diff)
downloadsystemd-a459b24f7e4d9030135e4ea40575d42f4a8fffdf.tar.xz
systemd-a459b24f7e4d9030135e4ea40575d42f4a8fffdf.zip
networkctl: optionally show link statistics
Diffstat (limited to 'src/network/networkctl.c')
-rw-r--r--src/network/networkctl.c65
1 files changed, 62 insertions, 3 deletions
diff --git a/src/network/networkctl.c b/src/network/networkctl.c
index b924247af7..d61a20c42d 100644
--- a/src/network/networkctl.c
+++ b/src/network/networkctl.c
@@ -45,6 +45,7 @@
static PagerFlags arg_pager_flags = 0;
static bool arg_legend = true;
static bool arg_all = false;
+static bool arg_stats = false;
static char *link_get_type_string(unsigned short iftype, sd_device *d) {
const char *t, *devtype;
@@ -109,9 +110,16 @@ typedef struct LinkInfo {
uint32_t tx_queues;
uint32_t rx_queues;
+ union {
+ struct rtnl_link_stats64 stats64;
+ struct rtnl_link_stats stats;
+ };
+
bool has_mac_address:1;
bool has_tx_queues:1;
bool has_rx_queues:1;
+ bool has_stats64:1;
+ bool has_stats:1;
} LinkInfo;
static int link_info_compare(const LinkInfo *a, const LinkInfo *b) {
@@ -173,6 +181,11 @@ static int decode_link(sd_netlink_message *m, LinkInfo *info, char **patterns) {
sd_netlink_message_read_u32(m, IFLA_NUM_TX_QUEUES, &info->tx_queues) >= 0 &&
info->tx_queues > 0;
+ if (sd_netlink_message_read(m, IFLA_STATS64, sizeof info->stats64, &info->stats64) >= 0)
+ info->has_stats64 = true;
+ else if (sd_netlink_message_read(m, IFLA_STATS, sizeof info->stats, &info->stats) >= 0)
+ info->has_stats = true;
+
return 1;
}
@@ -799,6 +812,42 @@ static int dump_list(Table *table, const char *prefix, char **l) {
return 0;
}
+#define DUMP_STATS_ONE(name, val_name) \
+ r = table_add_cell(table, NULL, TABLE_EMPTY, NULL); \
+ if (r < 0) \
+ return r; \
+ r = table_add_cell_full(table, NULL, TABLE_STRING, name ":", \
+ SIZE_MAX, SIZE_MAX, 0, 100, 0); \
+ if (r < 0) \
+ return r; \
+ r = table_add_cell(table, NULL, info->has_stats64 ? TABLE_UINT64 : TABLE_UINT32, \
+ info->has_stats64 ? (void*) &info->stats64.val_name : (void*) &info->stats.val_name); \
+ if (r < 0) \
+ return r;
+
+static int dump_statistics(Table *table, const LinkInfo *info) {
+ int r;
+
+ if (!arg_stats)
+ return 0;
+
+ if (!info->has_stats64 && !info->has_stats)
+ return 0;
+
+ DUMP_STATS_ONE("Rx Packets", rx_packets);
+ DUMP_STATS_ONE("Tx Packets", tx_packets);
+ DUMP_STATS_ONE("Rx Bytes", rx_bytes);
+ DUMP_STATS_ONE("Tx Bytes", tx_bytes);
+ DUMP_STATS_ONE("Rx Errors", rx_errors);
+ DUMP_STATS_ONE("Tx Errors", tx_errors);
+ DUMP_STATS_ONE("Rx Dropped", rx_dropped);
+ DUMP_STATS_ONE("Tx Dropped", tx_dropped);
+ DUMP_STATS_ONE("Multicast Packets", multicast);
+ DUMP_STATS_ONE("Collisions", collisions);
+
+ return 0;
+}
+
static int link_status_one(
sd_netlink *rtnl,
sd_hwdb *hwdb,
@@ -1061,6 +1110,10 @@ static int link_status_one(
if (r < 0)
return r;
+ r = dump_statistics(table, info);
+ if (r < 0)
+ return r;
+
return table_print(table, NULL);
}
@@ -1415,8 +1468,9 @@ static int help(void) {
" --version Show package version\n"
" --no-pager Do not pipe output into a pager\n"
" --no-legend Do not show the headers and footers\n"
- " -a --all Show status for all links\n\n"
- "Commands:\n"
+ " -a --all Show status for all links\n"
+ " -s --stats Show detailed link statics\n"
+ "\nCommands:\n"
" list [PATTERN...] List links\n"
" status [PATTERN...] Show link status\n"
" lldp [PATTERN...] Show LLDP neighbors\n"
@@ -1444,6 +1498,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "no-pager", no_argument, NULL, ARG_NO_PAGER },
{ "no-legend", no_argument, NULL, ARG_NO_LEGEND },
{ "all", no_argument, NULL, 'a' },
+ { "stats", no_argument, NULL, 's' },
{}
};
@@ -1452,7 +1507,7 @@ static int parse_argv(int argc, char *argv[]) {
assert(argc >= 0);
assert(argv);
- while ((c = getopt_long(argc, argv, "ha", options, NULL)) >= 0) {
+ while ((c = getopt_long(argc, argv, "has", options, NULL)) >= 0) {
switch (c) {
@@ -1474,6 +1529,10 @@ static int parse_argv(int argc, char *argv[]) {
arg_all = true;
break;
+ case 's':
+ arg_stats = true;
+ break;
+
case '?':
return -EINVAL;