Files
MeshCore/tools/hil/ethernet_tcp_stats.py
T

54 lines
2.6 KiB
Python

#!/usr/bin/env python3
"""Summarize only the two explicitly captured isolated-namespace TCP snapshots."""
from __future__ import annotations
import argparse
import json
from pathlib import Path
FIELDS = ("ActiveOpens", "PassiveOpens", "AttemptFails", "EstabResets", "CurrEstab",
"InSegs", "OutSegs", "RetransSegs", "InErrs", "OutRsts", "InCsumErrors")
def parse_tcp(text):
lines = [line.split() for line in text.splitlines() if line.startswith("Tcp:")]
if len(lines) != 2 or len(lines[0]) != len(lines[1]) or len(set(lines[0])) != len(lines[0]):
raise ValueError("missing or ambiguous TCP header/value pair")
values = dict(zip(lines[0][1:], map(int, lines[1][1:])))
if any(values.get(field, -1) < 0 for field in ("InSegs", "OutSegs", "RetransSegs")):
raise ValueError("required TCP counters are missing or negative")
return {field: values[field] for field in FIELDS if field in values}
def summarize(before, after):
delta = {field: after[field] - before[field] for field in before.keys() & after.keys()
if field != "CurrEstab"}
if any(value < 0 for value in delta.values()):
raise ValueError("TCP counters decreased; snapshots are not comparable")
return dict(available=True, scope="isolated_network_namespace", before=before, after=after,
delta=delta, retransmission_scope="total only: includes SSH handshake, commands, data and close; no data-only attribution",
out_segment_retransmission_ratio=(delta["RetransSegs"] / delta["OutSegs"]
if delta["OutSegs"] else None))
def main(argv=None):
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--directory", required=True, type=Path)
args = parser.parse_args(argv)
folder = args.directory
if not folder.is_absolute() or not folder.is_dir():
parser.error("an existing absolute evidence directory is required")
try:
result = summarize(*(parse_tcp((folder / f"tcp-{phase}.snmp").read_text(encoding="ascii"))
for phase in ("before", "after")))
result["captured_utc"] = {phase: (folder / f"tcp-{phase}.utc").read_text(encoding="ascii").strip()
for phase in ("before", "after")}
except (OSError, ValueError) as error:
result = dict(available=False, scope="isolated_network_namespace", error=str(error))
(folder / "tcp-stats.json").write_text(json.dumps(result, indent=2, sort_keys=True) + "\n", encoding="utf-8")
return 0
if __name__ == "__main__":
raise SystemExit(main())