Skip to content

Commit

Permalink
Added live traffic stats counting and output to rnstatus
Browse files Browse the repository at this point in the history
  • Loading branch information
markqvist committed Jan 11, 2025
1 parent 45494f2 commit ab5fcd7
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 10 deletions.
20 changes: 18 additions & 2 deletions RNS/Reticulum.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,8 +172,8 @@ def exit_handler():
RNS.Transport.exit_handler()
RNS.Identity.exit_handler()

if RNS.Profiler.ran():
RNS.Profiler.results()
# if RNS.Profiler.ran():
# RNS.Profiler.results()

@staticmethod
def sigint_handler(signal, frame):
Expand Down Expand Up @@ -965,6 +965,18 @@ def get_interface_stats(self):
else:
ifstats["bitrate"] = None

if hasattr(interface, "current_rx_speed"):
if interface.current_rx_speed != None:
ifstats["rxs"] = interface.current_rx_speed
else:
ifstats["rxs"] = 0

if hasattr(interface, "current_tx_speed"):
if interface.current_tx_speed != None:
ifstats["txs"] = interface.current_tx_speed
else:
ifstats["txs"] = 0

if hasattr(interface, "peers"):
if interface.peers != None:
ifstats["peers"] = len(interface.peers)
Expand Down Expand Up @@ -1002,6 +1014,10 @@ def get_interface_stats(self):

stats = {}
stats["interfaces"] = interfaces
stats["rxb"] = RNS.Transport.traffic_rxb
stats["txb"] = RNS.Transport.traffic_txb
stats["rxs"] = RNS.Transport.speed_rx
stats["txs"] = RNS.Transport.speed_tx
if Reticulum.transport_enabled():
stats["transport_id"] = RNS.Transport.identity.hash
stats["transport_uptime"] = time.time()-RNS.Transport.start_time
Expand Down
43 changes: 43 additions & 0 deletions RNS/Transport.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,12 @@ class Transport:
interface_last_jobs = 0.0
interface_jobs_interval = 5.0

traffic_rxb = 0
traffic_txb = 0
speed_rx = 0
speed_tx = 0
traffic_captured = None

identity = None

@staticmethod
Expand Down Expand Up @@ -195,6 +201,9 @@ def start(reticulum_instance):
thread = threading.Thread(target=Transport.jobloop, daemon=True)
thread.start()

thread = threading.Thread(target=Transport.count_traffic_loop, daemon=True)
thread.start()

if RNS.Reticulum.transport_enabled():
destination_table_path = RNS.Reticulum.storagepath+"/destination_table"
tunnel_table_path = RNS.Reticulum.storagepath+"/tunnels"
Expand Down Expand Up @@ -321,6 +330,40 @@ def prioritize_interfaces():
except Exception as e:
RNS.log(f"Could not prioritize interfaces according to bitrate. The contained exception was: {e}", RNS.LOG_ERROR)

@staticmethod
def count_traffic_loop():
while True:
time.sleep(1)
try:
rxb = 0; txb = 0;
rxs = 0; txs = 0;
for interface in Transport.interfaces:
if not hasattr(interface, "parent_interface") or interface.parent_interface == None:
if hasattr(interface, "transport_traffic_counter"):
now = time.time(); irxb = interface.rxb; itxb = interface.txb
tc = interface.transport_traffic_counter
rx_diff = irxb - tc["rxb"]
tx_diff = itxb - tc["txb"]
ts_diff = now - tc["ts"]
rxb += rx_diff; crxs = (rx_diff*8)/ts_diff
txb += tx_diff; ctxs = (tx_diff*8)/ts_diff
interface.current_rx_speed = crxs; rxs += crxs
interface.current_tx_speed = ctxs; txs += ctxs
tc["rxb"] = irxb;
tc["txb"] = itxb;
tc["ts"] = now;

else:
interface.transport_traffic_counter = {"ts": time.time(), "rxb": interface.rxb, "txb": interface.txb}

Transport.traffic_rxb += rxb
Transport.traffic_txb += txb
Transport.speed_rx = rxs
Transport.speed_tx = txs

except Exception as e:
RNS.log(f"An error occurred while counting interface traffic: {e}", RNS.LOG_ERROR)

@staticmethod
def jobloop():
while (True):
Expand Down
43 changes: 40 additions & 3 deletions RNS/Utilities/rnstatus.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ def remote_link_established(link):

def program_setup(configdir, dispall=False, verbosity=0, name_filter=None, json=False, astats=False,
lstats=False, sorting=None, sort_reverse=False, remote=None, management_identity=None,
remote_timeout=RNS.Transport.PATH_REQUEST_TIMEOUT, must_exit=True, rns_instance=None):
remote_timeout=RNS.Transport.PATH_REQUEST_TIMEOUT, must_exit=True, rns_instance=None, traffic_totals=False):

if remote:
require_shared = False
Expand Down Expand Up @@ -228,6 +228,10 @@ def program_setup(configdir, dispall=False, verbosity=0, name_filter=None, json=
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":
Expand Down Expand Up @@ -364,7 +368,18 @@ def program_setup(configdir, dispall=False, verbosity=0, name_filter=None, json=
print(" Announces : {iaf}↑".format(iaf=RNS.prettyfrequency(ifstat["outgoing_announce_frequency"])))
print(" {iaf}↓".format(iaf=RNS.prettyfrequency(ifstat["incoming_announce_frequency"])))

print(" Traffic : {txb}↑\n {rxb}↓".format(rxb=size_str(ifstat["rxb"]), txb=size_str(ifstat["txb"])))
rxb_str = "↓"+RNS.prettysize(ifstat["rxb"])
txb_str = "↑"+RNS.prettysize(ifstat["txb"])
strdiff = len(rxb_str)-len(txb_str)
if strdiff > 0:
txb_str += " "*strdiff
elif strdiff < 0:
rxb_str += " "*-strdiff

rxstat = rxb_str+" "+RNS.prettyspeed(ifstat["rxs"])
txstat = txb_str+" "+RNS.prettyspeed(ifstat["txs"])

print(f" Traffic : {txstat}\n {rxstat}")

lstr = ""
if link_count != None and lstats:
Expand All @@ -374,6 +389,19 @@ def program_setup(configdir, dispall=False, verbosity=0, name_filter=None, json=
else:
lstr = f" {link_count} entr{ms} in link table"

if traffic_totals:
rxb_str = "↓"+RNS.prettysize(stats["rxb"])
txb_str = "↑"+RNS.prettysize(stats["txb"])
strdiff = len(rxb_str)-len(txb_str)
if strdiff > 0:
txb_str += " "*strdiff
elif strdiff < 0:
rxb_str += " "*-strdiff

rxstat = rxb_str+" "+RNS.prettyspeed(stats["rxs"])
txstat = txb_str+" "+RNS.prettyspeed(stats["txs"])
print(f"\n Totals : {txstat}\n {rxstat}")

if "transport_id" in stats and stats["transport_id"] != None:
print("\n Transport Instance "+RNS.prettyhexrep(stats["transport_id"])+" running")
if "probe_responder" in stats and stats["probe_responder"] != None:
Expand Down Expand Up @@ -426,11 +454,19 @@ def main(must_exit=True, rns_instance=None):
default=False,
)

parser.add_argument(
"-t",
"--totals",
action="store_true",
help="display traffic totals",
default=False,
)

parser.add_argument(
"-s",
"--sort",
action="store",
help="sort interfaces by [rate, traffic, rx, tx, announces, arx, atx, held]",
help="sort interfaces by [rate, traffic, rx, tx, rxs, txs, announces, arx, atx, held]",
default=None,
type=str
)
Expand Down Expand Up @@ -504,6 +540,7 @@ def main(must_exit=True, rns_instance=None):
remote_timeout=args.w,
must_exit=must_exit,
rns_instance=rns_instance,
traffic_totals=args.totals,
)

except KeyboardInterrupt:
Expand Down
10 changes: 5 additions & 5 deletions RNS/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -481,10 +481,10 @@ def print_tag_results(tag, level):
print(f"{ind} St.dev. : {prettyshorttime(stdev)}")
print("")

print("\nProfiler results:\n")
for tag_name in results:
tag = results[tag_name]
if tag["super"] == None:
print_results_recursive(tag, results)
print("\nProfiler results:\n")
for tag_name in results:
tag = results[tag_name]
if tag["super"] == None:
print_results_recursive(tag, results)

profile = Profiler.get_profiler

0 comments on commit ab5fcd7

Please sign in to comment.