diff --git a/CHANGELOG.md b/CHANGELOG.md index 88880fd..5a1b61b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,8 @@ * river: support for the new “mode” event present in version 3 of the river status manager protocol, in the form of a new tag, _”mode”_, in the `title` particle. +* network: request link stats and expose under tags `dl-speed` and + `ul-speed` when `poll-interval` is set. [153]: https://codeberg.org/dnkl/yambar/issues/153 diff --git a/doc/yambar-modules-network.5.scd b/doc/yambar-modules-network.5.scd index 6b5e835..d8129ef 100644 --- a/doc/yambar-modules-network.5.scd +++ b/doc/yambar-modules-network.5.scd @@ -51,6 +51,12 @@ address. | tx-bitrate : int : TX bitrate in bits/s +| dl-speed +: int +: Download speed in bits/s +| ul-speed +: int +: Upload speed in bits/s # CONFIGURATION @@ -66,7 +72,8 @@ address. | poll-interval : int : no -: Periodically (in seconds) update the signal and rx+tx bitrate tags. +: Periodically (in seconds) update the signal, rx+tx bitrate, and + ul+dl speed tags. # EXAMPLES diff --git a/examples/configurations/laptop.conf b/examples/configurations/laptop.conf index 573516c..c02ba4a 100644 --- a/examples/configurations/laptop.conf +++ b/examples/configurations/laptop.conf @@ -185,6 +185,7 @@ bar: ipv4 == "": {string: {text: , font: *awesome, foreground: ffffff66}} - network: name: wlp2s0 + poll-interval: 1 content: map: default: {string: {text: , font: *awesome, foreground: ffffff66}} @@ -194,11 +195,12 @@ bar: map: default: - string: {text: , font: *awesome} - - string: {text: "{ssid}"} + - string: {text: "{ssid} {dl-speed:mb}/{ul-speed:mb} Mb/s"} + conditions: ipv4 == "": - string: {text: , font: *awesome, foreground: ffffff66} - - string: {text: "{ssid}", foreground: ffffff66} + - string: {text: "{ssid} {dl-speed:mb}/{ul-speed:mb} Mb/s", foreground: ffffff66} - alsa: card: hw:PCH mixer: Master diff --git a/modules/network.c b/modules/network.c index ef7366b..9ec5993 100644 --- a/modules/network.c +++ b/modules/network.c @@ -31,6 +31,11 @@ #define UNUSED __attribute__((unused)) +struct rt_stats_msg { + struct rtmsg rth; + struct rtnl_link_stats64 stats; +}; + struct af_addr { int family; union { @@ -68,6 +73,12 @@ struct private { int signal_strength_dbm; uint32_t rx_bitrate; uint32_t tx_bitrate; + + uint64_t ul_speed; + uint64_t ul_bits; + + uint64_t dl_speed; + uint64_t dl_bits; }; static void @@ -145,8 +156,10 @@ content(struct module *mod) tag_new_int(mod, "signal", m->signal_strength_dbm), tag_new_int(mod, "rx-bitrate", m->rx_bitrate), tag_new_int(mod, "tx-bitrate", m->tx_bitrate), + tag_new_float(mod, "dl-speed", m->dl_speed), + tag_new_float(mod, "ul-speed", m->ul_speed), }, - .count = 11, + .count = 13, }; mtx_unlock(&mod->lock); @@ -252,6 +265,36 @@ send_rt_request(struct private *m, int request) return true; } +static bool +send_rt_getstats_request(struct private *m) +{ + struct { + struct nlmsghdr hdr; + struct if_stats_msg rt; + } req = { + .hdr = { + .nlmsg_len = NLMSG_LENGTH(sizeof(req.rt)), + .nlmsg_type = RTM_GETSTATS, + .nlmsg_flags = NLM_F_REQUEST, + .nlmsg_seq = 1, + .nlmsg_pid = nl_pid_value(), + }, + + .rt = { + .ifindex = m->ifindex, + .filter_mask = IFLA_STATS_LINK_64, + .family = AF_UNSPEC, + }, + }; + + if (!send_nlmsg(m->rt_sock, &req, req.hdr.nlmsg_len)) { + LOG_ERRNO("%s: failed to send netlink RT getstats request (%d)", + m->iface, RTM_GETSTATS); + return false; + } + return true; +} + static bool send_ctrl_get_family_request(struct private *m) { @@ -929,6 +972,23 @@ netlink_receive_messages(int sock, void **reply, size_t *len) return true; } +static void +handle_stats(struct module *mod, struct rt_stats_msg *msg) +{ + struct private *m = mod->private; + uint64_t ul_bits = msg->stats.tx_bytes*8; + uint64_t dl_bits = msg->stats.rx_bytes*8; + + if (m->ul_bits != 0) { + m->ul_speed = (ul_bits - m->ul_bits) / m->poll_interval; + } + if (m->dl_bits != 0) { + m->dl_speed = (dl_bits - m->dl_bits) / m->poll_interval; + } + m->ul_bits = ul_bits; + m->dl_bits = dl_bits; +} + static bool parse_rt_reply(struct module *mod, const struct nlmsghdr *hdr, size_t len) { @@ -967,6 +1027,11 @@ parse_rt_reply(struct module *mod, const struct nlmsghdr *hdr, size_t len) handle_address(mod, hdr->nlmsg_type, msg, msg_len); break; } + case RTM_NEWSTATS: { + struct rt_stats_msg *msg = NLMSG_DATA(hdr); + handle_stats(mod, msg); + break; + } case NLMSG_ERROR:{ const struct nlmsgerr *err = NLMSG_DATA(hdr); @@ -1200,6 +1265,7 @@ run(struct module *mod) } send_nl80211_get_station(m); + send_rt_getstats_request(m); } }