summaryrefslogtreecommitdiffstats
path: root/src/network/networkctl.c
diff options
context:
space:
mode:
authorYu Watanabe <watanabe.yu+github@gmail.com>2019-05-25 17:22:05 +0200
committerYu Watanabe <watanabe.yu+github@gmail.com>2019-06-01 03:24:47 +0200
commit335dd8ba1398379a411e7be96bc2896574b39d45 (patch)
tree2ded73e9ead4fe36243259f85e1d6bb80eeb3d66 /src/network/networkctl.c
parentnetwork: monitor link bit rates (diff)
downloadsystemd-335dd8ba1398379a411e7be96bc2896574b39d45.tar.xz
systemd-335dd8ba1398379a411e7be96bc2896574b39d45.zip
networkctl: show link bit rates
Diffstat (limited to 'src/network/networkctl.c')
-rw-r--r--src/network/networkctl.c123
1 files changed, 117 insertions, 6 deletions
diff --git a/src/network/networkctl.c b/src/network/networkctl.c
index d61a20c42d..2038571c0c 100644
--- a/src/network/networkctl.c
+++ b/src/network/networkctl.c
@@ -8,6 +8,7 @@
#include <sys/types.h>
#include <unistd.h>
+#include "sd-bus.h"
#include "sd-device.h"
#include "sd-hwdb.h"
#include "sd-lldp.h"
@@ -16,6 +17,9 @@
#include "alloc-util.h"
#include "arphrd-list.h"
+#include "bus-common-errors.h"
+#include "bus-error.h"
+#include "bus-util.h"
#include "device-util.h"
#include "ether-addr-util.h"
#include "fd-util.h"
@@ -115,11 +119,15 @@ typedef struct LinkInfo {
struct rtnl_link_stats stats;
};
+ double tx_bitrate;
+ double rx_bitrate;
+
bool has_mac_address:1;
bool has_tx_queues:1;
bool has_rx_queues:1;
bool has_stats64:1;
bool has_stats:1;
+ bool has_bitrates:1;
} LinkInfo;
static int link_info_compare(const LinkInfo *a, const LinkInfo *b) {
@@ -189,10 +197,57 @@ static int decode_link(sd_netlink_message *m, LinkInfo *info, char **patterns) {
return 1;
}
-static int acquire_link_info(sd_netlink *rtnl, char **patterns, LinkInfo **ret) {
+static int acquire_link_bitrates(sd_bus *bus, LinkInfo *link) {
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_free_ char *path = NULL, *ifindex_str = NULL;
+ int r;
+
+ if (asprintf(&ifindex_str, "%i", link->ifindex) < 0)
+ return -ENOMEM;
+
+ r = sd_bus_path_encode("/org/freedesktop/network1/link", ifindex_str, &path);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_call_method(
+ bus,
+ "org.freedesktop.network1",
+ path,
+ "org.freedesktop.DBus.Properties",
+ "Get",
+ &error,
+ &reply,
+ "ss",
+ "org.freedesktop.network1.Link",
+ "BitRates");
+ if (r < 0) {
+ if (sd_bus_error_has_name(&error, BUS_ERROR_SPEED_METER_INACTIVE))
+ return 0;
+ return log_error_errno(r, "%s", bus_error_message(&error, r));
+ }
+
+ r = sd_bus_message_enter_container(reply, 'v', "(dd)");
+ if (r < 0)
+ return bus_log_parse_error(r);
+
+ r = sd_bus_message_read(reply, "(dd)", &link->tx_bitrate, &link->rx_bitrate);
+ if (r < 0)
+ return bus_log_parse_error(r);
+
+ r = sd_bus_message_exit_container(reply);
+ if (r < 0)
+ return bus_log_parse_error(r);
+
+ link->has_bitrates = link->tx_bitrate >= 0 && link->rx_bitrate >= 0;
+
+ return 0;
+}
+
+static int acquire_link_info(sd_bus *bus, sd_netlink *rtnl, char **patterns, LinkInfo **ret) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
_cleanup_free_ LinkInfo *links = NULL;
- size_t allocated = 0, c = 0;
+ size_t allocated = 0, c = 0, j;
sd_netlink_message *i;
int r;
@@ -224,6 +279,10 @@ static int acquire_link_info(sd_netlink *rtnl, char **patterns, LinkInfo **ret)
typesafe_qsort(links, c, link_info_compare);
+ if (bus)
+ for (j = 0; j < c; j++)
+ (void) acquire_link_bitrates(bus, links + j);
+
*ret = TAKE_PTR(links);
return (int) c;
@@ -240,7 +299,7 @@ static int list_links(int argc, char *argv[], void *userdata) {
if (r < 0)
return log_error_errno(r, "Failed to connect to netlink: %m");
- c = acquire_link_info(rtnl, argc > 1 ? argv + 1 : NULL, &links);
+ c = acquire_link_info(NULL, rtnl, argc > 1 ? argv + 1 : NULL, &links);
if (c < 0)
return c;
@@ -848,6 +907,32 @@ static int dump_statistics(Table *table, const LinkInfo *info) {
return 0;
}
+static const struct {
+ double val;
+ const char *str;
+} prefix_table[] = {
+ { .val = 1e15, .str = "P" },
+ { .val = 1e12, .str = "T" },
+ { .val = 1e9, .str = "G" },
+ { .val = 1e6, .str = "M" },
+ { .val = 1e3, .str = "k" },
+};
+
+static void get_prefix(double val, double *ret_div, const char **ret_prefix) {
+ assert(ret_div);
+ assert(ret_prefix);
+
+ for (size_t i = 0; i < ELEMENTSOF(prefix_table); i++)
+ if (val > prefix_table[i].val) {
+ *ret_div = prefix_table[i].val;
+ *ret_prefix = prefix_table[i].str;
+ return;
+ }
+
+ *ret_div = 1;
+ *ret_prefix = NULL;
+}
+
static int link_status_one(
sd_netlink *rtnl,
sd_hwdb *hwdb,
@@ -1056,6 +1141,27 @@ static int link_status_one(
return r;
}
+ if (info->has_bitrates) {
+ const char *tx_prefix, *rx_prefix;
+ double tx_div, rx_div;
+
+ get_prefix(info->tx_bitrate, &tx_div, &tx_prefix);
+ get_prefix(info->rx_bitrate, &rx_div, &rx_prefix);
+
+ r = table_add_cell(table, NULL, TABLE_EMPTY, NULL);
+ if (r < 0)
+ return r;
+ r = table_add_cell_full(table, NULL, TABLE_STRING, "Bit Rate (Tx/Rx):", SIZE_MAX, SIZE_MAX, 0, 100, 0);
+ if (r < 0)
+ return r;
+
+ r = table_add_cell_stringf(table, NULL, "%.4g %sbps/%.4g %sbps",
+ info->tx_bitrate / tx_div, strempty(tx_prefix),
+ info->rx_bitrate / rx_div, strempty(rx_prefix));
+ if (r < 0)
+ return r;
+ }
+
if (info->has_tx_queues || info->has_rx_queues) {
r = table_add_cell(table, NULL, TABLE_EMPTY, NULL);
if (r < 0)
@@ -1182,6 +1288,7 @@ static int system_status(sd_netlink *rtnl, sd_hwdb *hwdb) {
}
static int link_status(int argc, char *argv[], void *userdata) {
+ _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
_cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
_cleanup_(sd_hwdb_unrefp) sd_hwdb *hwdb = NULL;
_cleanup_free_ LinkInfo *links = NULL;
@@ -1189,6 +1296,10 @@ static int link_status(int argc, char *argv[], void *userdata) {
(void) pager_open(arg_pager_flags);
+ r = sd_bus_open_system(&bus);
+ if (r < 0)
+ return log_error_errno(r, "Failed to connect system bus: %m");
+
r = sd_netlink_open(&rtnl);
if (r < 0)
return log_error_errno(r, "Failed to connect to netlink: %m");
@@ -1198,11 +1309,11 @@ static int link_status(int argc, char *argv[], void *userdata) {
log_debug_errno(r, "Failed to open hardware database: %m");
if (arg_all)
- c = acquire_link_info(rtnl, NULL, &links);
+ c = acquire_link_info(bus, rtnl, NULL, &links);
else if (argc <= 1)
return system_status(rtnl, hwdb);
else
- c = acquire_link_info(rtnl, argv + 1, &links);
+ c = acquire_link_info(bus, rtnl, argv + 1, &links);
if (c < 0)
return c;
@@ -1278,7 +1389,7 @@ static int link_lldp_status(int argc, char *argv[], void *userdata) {
if (r < 0)
return log_error_errno(r, "Failed to connect to netlink: %m");
- c = acquire_link_info(rtnl, argc > 1 ? argv + 1 : NULL, &links);
+ c = acquire_link_info(NULL, rtnl, argc > 1 ? argv + 1 : NULL, &links);
if (c < 0)
return c;