From fe53aeae0138c063a3fe08a67c29ec82f83e622a Mon Sep 17 00:00:00 2001 From: Wajeeh Jafry Date: Fri, 24 Jul 2026 15:15:45 -0500 Subject: [PATCH] finished issue --- lpcpu.sh | 61 ++++++++- .../__pycache__/ip_to_netstat.cpython-314.pyc | Bin 0 -> 4457 bytes tools/ip_to_netstat.py | 116 ++++++++++++++++++ 3 files changed, 171 insertions(+), 6 deletions(-) create mode 100644 tools/__pycache__/ip_to_netstat.cpython-314.pyc create mode 100755 tools/ip_to_netstat.py diff --git a/lpcpu.sh b/lpcpu.sh index fef78bd..2391f2f 100755 --- a/lpcpu.sh +++ b/lpcpu.sh @@ -1138,6 +1138,55 @@ function sigint_running_trap() { #################################################################################################### +## Network statistics helper functions ############################################################# + +function has_netstat() { command -v netstat > /dev/null 2>&1; } +function has_ss() { command -v ss > /dev/null 2>&1; } +function has_nstat() { command -v nstat > /dev/null 2>&1; } +function has_iproute2() { command -v ip > /dev/null 2>&1 && ip -V > /dev/null 2>&1; } + +# Collect active socket statistics (netstat -v preferred; ss fallback) +function collect_active_socket_statistics() { + local output_file="$1" + if has_netstat; then + netstat -v > "$output_file" 2>&1 + elif has_ss; then + ss > "$output_file" 2>&1 + else + echo "netstat nor ss not available" > "$output_file" + fi +} + +# Collect kernel network protocol statistics (netstat -s preferred; nstat fallback) +function kernel_network_protocol_statistics() { + local output_file="$1" + if has_netstat; then + netstat -s > "$output_file" 2>&1 + elif has_nstat; then + nstat -az > "$output_file" 2>&1 + else + echo "netstat nor nstat not available" > "$output_file" + fi +} + +# Collect kernel interface table (netstat -in preferred; ip -s link fallback) +function kernel_interface_table() { + local output_file="$1" + local formatting_script="${LPCPUDIR}/tools/ip_to_netstat.py" + local temp_file="${output_file}.tmp" + if has_netstat; then + netstat -in > "$output_file" 2>&1 + elif has_iproute2; then + ip -s link > "$temp_file" 2>&1 + python3 "$formatting_script" "$temp_file" > "$output_file" 2>&1 + rm -f "$temp_file" + else + echo "netstat nor ip not available" > "$output_file" + fi +} + +#################################################################################################### + # main block, used to log all output { trap sigint_normal_trap SIGINT @@ -1158,9 +1207,9 @@ function sigint_running_trap() { done cat /proc/net/netstat > $LOGDIR/netstat.before - netstat -in > $LOGDIR/netstat-in.before 2>&1 - netstat -v > $LOGDIR/netstat-v.before 2>&1 - netstat -s > $LOGDIR/netstat-s.before 2>&1 + kernel_interface_table "$LOGDIR/netstat-in.before" + collect_active_socket_statistics "$LOGDIR/netstat-v.before" + kernel_network_protocol_statistics "$LOGDIR/netstat-s.before" cat /proc/interrupts > $LOGDIR/interrupts.before cat /proc/meminfo > $LOGDIR/meminfo.before if (( depth > 1 )); then @@ -1218,9 +1267,9 @@ function sigint_running_trap() { trap sigint_normal_trap SIGINT cat /proc/net/netstat > $LOGDIR/netstat.after - netstat -in > $LOGDIR/netstat-in.after 2>&1 - netstat -v > $LOGDIR/netstat-v.after 2>&1 - netstat -s > $LOGDIR/netstat-s.after 2>&1 + kernel_interface_table "$LOGDIR/netstat-in.after" + collect_active_socket_statistics "$LOGDIR/netstat-v.after" + kernel_network_protocol_statistics "$LOGDIR/netstat-s.after" cat /proc/interrupts > $LOGDIR/interrupts.after cat /proc/meminfo > $LOGDIR/meminfo.after if (( depth > 1 )); then diff --git a/tools/__pycache__/ip_to_netstat.cpython-314.pyc b/tools/__pycache__/ip_to_netstat.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8ef2c291e6a832646a2ecbc0dabf1587aaba74a3 GIT binary patch literal 4457 zcmb^#ZA@F&^}a8EJlkNKZ<4?R+9VEvd~Rha1rib#k^s)dSg0j9FZKgWjQ#T7BLPd3 zkh-l-)(X-^!+$0*Y1OFqhiaRaKa=ujT7Oa{Rq0)%MQf$0`$bB$toyZdpZ$zYk~N!l zkem+VqA?FsYp^WbVD}U)p_Z!3wNYw zDtTSe4C!)QmD+SE5l>#dETv`*b=HuKl$6(&+Tux2P0Y?DrGz{W@^(=i(d9|yg!GKt z&bZp9w^2`RIY(_1@r2SPilHe*(xX~jH6%@uW4dGjgUTdTOT}iRN=&*kUmA&=jDawo zG;~Rp4EYM^8dI_%&d5e|O38UBiAzdNNSBMEzI;LyC8>Wxjw+Hg5E_vrJlZyN-b80G zHt}g3%(27p9m2A$}{yBP9FfiUl-QkcZLnJpDQo zVP@G`E>c(_l?gLJu-w_K6;xTw(7)q(oklbUJ>*)@W>MR?31N1WEz)sp%Pb0WujRd| zTsuQn7%(CqzYjn=(6;-aUmLz@5{3%!N+cNz5x|S^bWX$0=Z?29ngIqoRM$&d6~>&xZ)U# zYim%#FIq4bdM$Bb3gPOco9wyg#MrI2y>XQ zBSFH95XXg~q2Q^Lz2^yYfjCd$p_8Y3PY#C&bBZ_zMlOWI7))Hj zq5i?pkO>JBB=#U48t5PHCCnf}C3S%2)no88D|aW`46C+)La47Ap=-Wj_In`8=S|46 z!(5m-NGnIa&7lRM5uLBi?FNim(04dkX=d<46yOQlewZ*58tsADClZs98Clh7E!Zn9 zERbp=l}hM`cGh9y?3`4R%ABfok!F?dmk6ln5n7nrI}@p>oY1@43p(e)oxTUaKfi*w z*QB)lpcQ-qxWiJ{CH#C8QneN`u7 z;W+3-FnPo=1$`=7WJaS?ph0Cr5XW3(2225Jjg%`<&_qEC1+P%>Dh2e^nyaJL0i{<0 z*emU9Jv|y-a8kZwEwoPH`l#LC;i~Y>0{YVF$;1}x->qNLHp+dAH*Vhe$$W-?$|14x ziHOR)i=($jml7+df6M;f{gL~D=Z%HFN4|=Ma}Rwr8DYa)wd}g>`l%-){H46|b9dzv z8>*~c?s&gr!+mnY?Ynbyx$}1CmcUht8OKux^45aRBX8|;+3m9Iwfo+t48KwI^_h3y zC*FOl+bppddjiJ(#ra$F8}2c13@*K5hKC5B!+k2EmVHZ=%k{VGvnTKDS?z`B zn)jA4Y|k+MwnO73Og2U2@nw%~xT`6sDS#?U)lmS{X1Sw6%-A>m2xfQk=H#bzuivlg zxnI_k;T}2spE>G2anx-nSXQ9!3M34JcI~0QA z3+0&gKtMs70CqI1w2ZSIH{elFLyJg}#q%$Xh07FNFrAjeBCF^0GhULstX@^PfMU)A zmp&|D8(=$>L8ti*1=_^!JocE_4h1_WFVFM6dF(T>|7fMkj1?}W;i5>x$cy@Z1lLx! zNY3Jl;-s33CCuW=60R8;aH~qVW*oq+F5#L{1Gnb6+}dZjcF?UW;aYy{OSqQbUC-t2 zeuhi^?kVQF(a|bv-l1^3lP??%Ehy0V72PB0L;vObj0ol{Da~~rfodZW4qi)Xw(GlT zR+7?!`D#jYT}KY5Z9v1@2xJ{54euip!}};Ln9rxQE%$sfu_?|ypVET)fZEQnJM(HY z1imx5?xj4MVFv>?!X=@lk>g3NA6Vn?(|aN1E}(~Y@!eyK9XC7P{y~;`V6S`Va4kA+Io5rr9yofx^hv+0 z_*LyMYFC>+*md96ws3CKh9D&z%d{xixlWX6?w@ z=-n%81NZ#jrckvhu+Fp0CWizU1@k-SwmJ{VOI8k;95Pk-gs#B+L~{z<9EC6;`PHl_n3Q4_s;&Y z_2Vn+CoisF9RA;|) xVIK2NhTp12jQD3Her-F)Fx6kb$@&>_^8n)Ane+p$?sMMp + +The script reads the file produced by `ip -s link` and prints a table that +matches the column layout of `netstat -in`: + + Iface MTU RX-OK RX-ERR RX-DRP RX-OVR TX-OK TX-ERR TX-DRP TX-OVR Flg +""" + +import re +import sys + + +def parse_ip_s_link(path): + """Parse `ip -s link` output and return a list of interface dicts.""" + with open(path) as fh: + text = fh.read() + + # Each interface block starts with a numbered line like: + # 1: lo: mtu 65536 ... + blocks = re.split(r'(?=^\d+:)', text, flags=re.MULTILINE) + + interfaces = [] + for block in blocks: + block = block.strip() + if not block: + continue + + # Header line: index, name, flags, mtu + header_m = re.match( + r'^\d+:\s+(\S+?)(?:@\S+)?:\s+<([^>]*)>\s+mtu\s+(\d+)', + block, re.MULTILINE + ) + if not header_m: + continue + + name = header_m.group(1) + flags = header_m.group(2).split(',') + mtu = header_m.group(3) + + # RX stats line: " RX: bytes packets errors dropped missed mcast" + # followed by values on the next line. + rx_m = re.search( + r'RX:\s+bytes\s+packets\s+errors\s+dropped.*?\n\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)', + block + ) + # TX stats line + tx_m = re.search( + r'TX:\s+bytes\s+packets\s+errors\s+dropped.*?\n\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)', + block + ) + + rx_ok = rx_m.group(2) if rx_m else '0' + rx_err = rx_m.group(3) if rx_m else '0' + rx_drp = rx_m.group(4) if rx_m else '0' + + tx_ok = tx_m.group(2) if tx_m else '0' + tx_err = tx_m.group(3) if tx_m else '0' + tx_drp = tx_m.group(4) if tx_m else '0' + + # Build flags string similar to netstat (B=BROADCAST, L=LOOPBACK, + # M=MULTICAST, R=RUNNING, U=UP) + flg_map = { + 'UP': 'U', + 'LOOPBACK': 'L', + 'BROADCAST': 'B', + 'MULTICAST': 'M', + 'RUNNING': 'R', + 'POINTOPOINT': 'P', + 'PROMISC': 'N', + } + flg = ''.join(flg_map[f] for f in flg_map if f in flags) + + interfaces.append({ + 'name': name, + 'mtu': mtu, + 'rx_ok': rx_ok, + 'rx_err': rx_err, + 'rx_drp': rx_drp, + 'rx_ovr': '0', + 'tx_ok': tx_ok, + 'tx_err': tx_err, + 'tx_drp': tx_drp, + 'tx_ovr': '0', + 'flg': flg or 'U', + }) + + return interfaces + + +def main(): + if len(sys.argv) != 2: + sys.exit("Usage: ip_to_netstat.py ") + + interfaces = parse_ip_s_link(sys.argv[1]) + + header = ( + f"{'Iface':<10} {'MTU':>6} " + f"{'RX-OK':>10} {'RX-ERR':>8} {'RX-DRP':>8} {'RX-OVR':>8} " + f"{'TX-OK':>10} {'TX-ERR':>8} {'TX-DRP':>8} {'TX-OVR':>8} Flg" + ) + print(header) + + for i in interfaces: + print( + f"{i['name']:<10} {i['mtu']:>6} " + f"{i['rx_ok']:>10} {i['rx_err']:>8} {i['rx_drp']:>8} {i['rx_ovr']:>8} " + f"{i['tx_ok']:>10} {i['tx_err']:>8} {i['tx_drp']:>8} {i['tx_ovr']:>8} {i['flg']}" + ) + + +if __name__ == '__main__': + main()