From 9878b1837726109a3a9a5b4e59db067a3e40ca7a Mon Sep 17 00:00:00 2001 From: Mark Qvist Date: Fri, 28 Aug 2026 13:44:14 +0200 Subject: [PATCH] Added transmit buffer, TX drops and stalled status output to rnstatus --- RNS/Interfaces/Interface.py | 1 + RNS/Interfaces/util/TransmitBuffer.py | 3 +- RNS/Reticulum.py | 4 ++ RNS/Utilities/rnstatus.py | 73 ++++++++++++--------------- 4 files changed, 38 insertions(+), 43 deletions(-) diff --git a/RNS/Interfaces/Interface.py b/RNS/Interfaces/Interface.py index ca301f86..2c529d41 100755 --- a/RNS/Interfaces/Interface.py +++ b/RNS/Interfaces/Interface.py @@ -148,6 +148,7 @@ class Interface: self.ec_pr_freq = RNS.Reticulum.get_instance()._default_ec_pr_freq() self.egress_control = RNS.Reticulum.get_instance()._default_egress_control() self.held_announces = {} + self.transmit_buffer = None self.ia_freq_deque = deque(maxlen=Interface.IA_FREQ_SAMPLES) self.oa_freq_deque = deque(maxlen=Interface.OA_FREQ_SAMPLES) diff --git a/RNS/Interfaces/util/TransmitBuffer.py b/RNS/Interfaces/util/TransmitBuffer.py index 42ab9942..16ebc9e8 100644 --- a/RNS/Interfaces/util/TransmitBuffer.py +++ b/RNS/Interfaces/util/TransmitBuffer.py @@ -151,8 +151,7 @@ class TransmitBuffer: self._head_offset = 0 # Total number of bytes currently buffered, including the - # producer's in-progress coalescing chunk. This value can - # be used for high-water accounting. + # producer's in-progress coalescing chunk. def __len__(self): return self._tx_total-self._tx_sent # The number of bytes actually ready to send, and will be diff --git a/RNS/Reticulum.py b/RNS/Reticulum.py index 03881f3b..77b742f5 100755 --- a/RNS/Reticulum.py +++ b/RNS/Reticulum.py @@ -1539,6 +1539,10 @@ class Reticulum: ifstats["ptxb"] = interface.ptxb ifstats["prxc"] = interface.prxc ifstats["ptxc"] = interface.ptxc + ifstats["txdrp"] = interface.tx_drops + ifstats["txdrb"] = interface.tx_dropped_bytes + ifstats["txstalled"] = interface.tx_stalled + ifstats["txbuffered"] = len(interface.transmit_buffer) if interface.transmit_buffer else 0 ifstats["incoming_announce_frequency"] = interface.incoming_announce_frequency() ifstats["outgoing_announce_frequency"] = interface.outgoing_announce_frequency() ifstats["incoming_pr_frequency"] = interface.incoming_pr_frequency() diff --git a/RNS/Utilities/rnstatus.py b/RNS/Utilities/rnstatus.py index f489d891..04754dfa 100644 --- a/RNS/Utilities/rnstatus.py +++ b/RNS/Utilities/rnstatus.py @@ -376,46 +376,29 @@ def program_setup(configdir, dispall=False, verbosity=0, name_filter=None, json= interfaces = stats["interfaces"] if sorting != None and isinstance(sorting, str): sorting = sorting.lower() - if sorting == "rate" or sorting == "bitrate": - interfaces.sort(key=lambda i: i["bitrate"], reverse=not sort_reverse) - if sorting == "rx": - interfaces.sort(key=lambda i: i["rxb"], reverse=not sort_reverse) - if sorting == "tx": - interfaces.sort(key=lambda i: i["txb"], reverse=not sort_reverse) - if sorting == "rxs": - interfaces.sort(key=lambda i: i["rxs"], reverse=not sort_reverse) - if sorting == "txs": - interfaces.sort(key=lambda i: i["txs"], reverse=not sort_reverse) - if sorting == "traffic": - interfaces.sort(key=lambda i: i["rxb"]+i["txb"], reverse=not sort_reverse) - if sorting == "announces" or sorting == "announce": - interfaces.sort(key=lambda i: i["incoming_announce_frequency"]+i["outgoing_announce_frequency"], reverse=not sort_reverse) - if sorting == "arx": - interfaces.sort(key=lambda i: i["incoming_announce_frequency"], reverse=not sort_reverse) - if sorting == "atx": - interfaces.sort(key=lambda i: i["outgoing_announce_frequency"], reverse=not sort_reverse) - if sorting == "arxc": - interfaces.sort(key=lambda i: i["arxc"], reverse=not sort_reverse) - if sorting == "atxc": - interfaces.sort(key=lambda i: i["atxc"], reverse=not sort_reverse) - if sorting == "prx": - interfaces.sort(key=lambda i: i["incoming_pr_frequency"], reverse=not sort_reverse) - if sorting == "ptx": - interfaces.sort(key=lambda i: i["outgoing_pr_frequency"], reverse=not sort_reverse) - if sorting == "prxc": - interfaces.sort(key=lambda i: i["prxc"], reverse=not sort_reverse) - if sorting == "ptxc": - interfaces.sort(key=lambda i: i["ptxc"], reverse=not sort_reverse) - if sorting == "held": - interfaces.sort(key=lambda i: i["held_announces"], reverse=not sort_reverse) - if sorting == "pvs": - interfaces.sort(key=lambda i: i["protocol_violations"], reverse=not sort_reverse) - if sorting == "ivs": - interfaces.sort(key=lambda i: i["ifac_violations"], reverse=not sort_reverse) - if sorting == "flt": - interfaces.sort(key=lambda i: i["packet_filter_hits"], reverse=not sort_reverse) - if sorting == "gravity" or sorting == "g": - interfaces.sort(key=lambda i: i["gravity"], reverse=not sort_reverse) + if sorting == "rate" or sorting == "bitrate": interfaces.sort(key=lambda i: i["bitrate"], reverse=not sort_reverse) + if sorting == "rx": interfaces.sort(key=lambda i: i["rxb"], reverse=not sort_reverse) + if sorting == "tx": interfaces.sort(key=lambda i: i["txb"], reverse=not sort_reverse) + if sorting == "rxs": interfaces.sort(key=lambda i: i["rxs"], reverse=not sort_reverse) + if sorting == "txs": interfaces.sort(key=lambda i: i["txs"], reverse=not sort_reverse) + if sorting == "traffic": interfaces.sort(key=lambda i: i["rxb"]+i["txb"], reverse=not sort_reverse) + if sorting == "anns" or sorting == "announces": interfaces.sort(key=lambda i: i["incoming_announce_frequency"]+i["outgoing_announce_frequency"], reverse=not sort_reverse) + if sorting == "arx": interfaces.sort(key=lambda i: i["incoming_announce_frequency"], reverse=not sort_reverse) + if sorting == "atx": interfaces.sort(key=lambda i: i["outgoing_announce_frequency"], reverse=not sort_reverse) + if sorting == "arxc": interfaces.sort(key=lambda i: i["arxc"], reverse=not sort_reverse) + if sorting == "atxc": interfaces.sort(key=lambda i: i["atxc"], reverse=not sort_reverse) + if sorting == "prx": interfaces.sort(key=lambda i: i["incoming_pr_frequency"], reverse=not sort_reverse) + if sorting == "ptx": interfaces.sort(key=lambda i: i["outgoing_pr_frequency"], reverse=not sort_reverse) + if sorting == "prxc": interfaces.sort(key=lambda i: i["prxc"], reverse=not sort_reverse) + if sorting == "ptxc": interfaces.sort(key=lambda i: i["ptxc"], reverse=not sort_reverse) + if sorting == "held": interfaces.sort(key=lambda i: i["held_announces"], reverse=not sort_reverse) + if sorting == "pvs": interfaces.sort(key=lambda i: i["protocol_violations"], reverse=not sort_reverse) + if sorting == "ivs": interfaces.sort(key=lambda i: i["ifac_violations"], reverse=not sort_reverse) + if sorting == "flt": interfaces.sort(key=lambda i: i["packet_filter_hits"], reverse=not sort_reverse) + if sorting == "gravity" or sorting == "g": interfaces.sort(key=lambda i: i["gravity"], reverse=not sort_reverse) + if sorting == "txdrp": interfaces.sort(key=lambda i: i["txdrp"], reverse=not sort_reverse) + if sorting == "txdrb": interfaces.sort(key=lambda i: i["txdrb"], reverse=not sort_reverse) + if sorting == "txbuf": interfaces.sort(key=lambda i: i["txbuffered"], reverse=not sort_reverse) for ifstat in interfaces: @@ -509,6 +492,9 @@ def program_setup(configdir, dispall=False, verbosity=0, name_filter=None, json= if not (name.startswith("Shared Instance[") or name.startswith("TCPInterface[Client") or name.startswith("LocalInterface[")): print(f" Mode : {modestr}") + if ifstat["txdrp"]: + print(f" TX Drops : {ifstat['txdrp']} ({RNS.prettysize(ifstat['txdrb'])})") + if "bitrate" in ifstat and ifstat["bitrate"] != None: print(f" Rate : {speed_str(ifstat['bitrate'])}, MTU {ifstat['mtu']}") @@ -710,6 +696,11 @@ def program_setup(configdir, dispall=False, verbosity=0, name_filter=None, json= if "rxs" in ifstat and "txs" in ifstat: rxstat += " "+RNS.prettyspeed(ifstat["rxs"]) txstat += " "+RNS.prettyspeed(ifstat["txs"]) + + if ifstat["txbuffered"]: + if ifstat["txstalled"]: stlstr = ", stalled" + else: stlstr = "" + txstat += f" ({RNS.prettysize(ifstat['txbuffered'])} waiting{stlstr})" print(f" Traffic : {txstat}\n {rxstat}") @@ -851,7 +842,7 @@ def main(must_exit=True, rns_instance=None): parser.add_argument("-p", "--pps", action="store_true", help="display packets per second in totals", default=False) parser.add_argument("-q", "--queues", action="store_true", help="display queue stats", default=False) parser.add_argument("-z", "--profiling", action="store_true", help="display live profiling results", default=False) - parser.add_argument("-s", "--sort", action="store", help="sort interfaces by [rate, traffic, rx, tx, rxs, txs, announces, arx, atx, arxc, atxc, held, prx, ptx, prxc, ptxc, pvs, ivs, flt]", default=None, type=str) + parser.add_argument("-s", "--sort", action="store", help="sort interfaces by [rate, traffic, rx, tx, rxs, txs, anns, arx, atx, arxc, atxc, held, prx, ptx, prxc, ptxc, pvs, ivs, flt, txdrp, txdrb, txbuf]", default=None, type=str) parser.add_argument("-r", "--reverse", action="store_true", help="reverse sorting", default=False) parser.add_argument("-j", "--json", action="store_true", help="output in JSON format", default=False) parser.add_argument("-R", action="store", metavar="hash", help="transport identity hash of remote instance to get status from", default=None, type=str)