Commit 2f64bf0b authored by Brendan Gregg's avatar Brendan Gregg Committed by GitHub

Merge pull request #1873 from andihit/tcptop-improvements

tcptop: fix display of received bytes, reduce syscalls (fixes #1871)
parents 10f718f4 c64f4872
...@@ -32,6 +32,7 @@ from struct import pack ...@@ -32,6 +32,7 @@ from struct import pack
from time import sleep, strftime from time import sleep, strftime
from subprocess import call from subprocess import call
import ctypes as ct import ctypes as ct
from collections import namedtuple, defaultdict
# arguments # arguments
def range_check(string): def range_check(string):
...@@ -188,6 +189,8 @@ if debug or args.ebpf: ...@@ -188,6 +189,8 @@ if debug or args.ebpf:
if args.ebpf: if args.ebpf:
exit() exit()
TCPSessionKey = namedtuple('TCPSession', ['pid', 'laddr', 'lport', 'daddr', 'dport'])
def pid_to_comm(pid): def pid_to_comm(pid):
try: try:
comm = open("/proc/%d/comm" % pid, "r").read().rstrip() comm = open("/proc/%d/comm" % pid, "r").read().rstrip()
...@@ -195,6 +198,20 @@ def pid_to_comm(pid): ...@@ -195,6 +198,20 @@ def pid_to_comm(pid):
except IOError: except IOError:
return str(pid) return str(pid)
def get_ipv4_session_key(k):
return TCPSessionKey(pid=k.pid,
laddr=inet_ntop(AF_INET, pack("I", k.saddr)),
lport=k.lport,
daddr=inet_ntop(AF_INET, pack("I", k.daddr)),
dport=k.dport)
def get_ipv6_session_key(k):
return TCPSessionKey(pid=k.pid,
laddr=inet_ntop(AF_INET6, pack("QQ", k.saddr0, k.saddr1)),
lport=k.lport,
daddr=inet_ntop(AF_INET6, pack("QQ", k.daddr0, k.daddr1)),
dport=k.dport)
# initialize BPF # initialize BPF
b = BPF(text=bpf_text) b = BPF(text=bpf_text)
...@@ -223,63 +240,57 @@ while i != args.count and not exiting: ...@@ -223,63 +240,57 @@ while i != args.count and not exiting:
with open(loadavg) as stats: with open(loadavg) as stats:
print("%-8s loadavg: %s" % (strftime("%H:%M:%S"), stats.read())) print("%-8s loadavg: %s" % (strftime("%H:%M:%S"), stats.read()))
# IPv4: build dict of all seen keys # IPv4: build dict of all seen keys
keys = ipv4_recv_bytes ipv4_throughput = defaultdict(lambda: [0, 0])
for k, v in ipv4_send_bytes.items(): for k, v in ipv4_send_bytes.items():
if k not in keys: key = get_ipv4_session_key(k)
keys[k] = v ipv4_throughput[key][0] = v.value
ipv4_send_bytes.clear()
if keys: for k, v in ipv4_recv_bytes.items():
key = get_ipv4_session_key(k)
ipv4_throughput[key][1] = v.value
ipv4_recv_bytes.clear()
if ipv4_throughput:
print("%-6s %-12s %-21s %-21s %6s %6s" % ("PID", "COMM", print("%-6s %-12s %-21s %-21s %6s %6s" % ("PID", "COMM",
"LADDR", "RADDR", "RX_KB", "TX_KB")) "LADDR", "RADDR", "RX_KB", "TX_KB"))
# output # output
for k, v in reversed(sorted(keys.items(), key=lambda keys: keys[1].value)): for k, (send_bytes, recv_bytes) in sorted(ipv4_throughput.items(),
send_kbytes = 0 key=lambda kv: sum(kv[1]),
if k in ipv4_send_bytes: reverse=True):
send_kbytes = int(ipv4_send_bytes[k].value / 1024)
recv_kbytes = 0
if k in ipv4_recv_bytes:
recv_kbytes = int(ipv4_recv_bytes[k].value / 1024)
print("%-6d %-12.12s %-21s %-21s %6d %6d" % (k.pid, print("%-6d %-12.12s %-21s %-21s %6d %6d" % (k.pid,
pid_to_comm(k.pid), pid_to_comm(k.pid),
inet_ntop(AF_INET, pack("I", k.saddr)) + ":" + str(k.lport), k.laddr + ":" + str(k.lport),
inet_ntop(AF_INET, pack("I", k.daddr)) + ":" + str(k.dport), k.daddr + ":" + str(k.dport),
recv_kbytes, send_kbytes)) int(recv_bytes / 1024), int(send_bytes / 1024)))
ipv4_send_bytes.clear()
ipv4_recv_bytes.clear()
# IPv6: build dict of all seen keys # IPv6: build dict of all seen keys
keys = ipv6_recv_bytes ipv6_throughput = defaultdict(lambda: [0, 0])
for k, v in ipv6_send_bytes.items(): for k, v in ipv6_send_bytes.items():
if k not in keys: key = get_ipv6_session_key(k)
keys[k] = v ipv6_throughput[key][0] = v.value
ipv6_send_bytes.clear()
for k, v in ipv6_recv_bytes.items():
key = get_ipv6_session_key(k)
ipv6_throughput[key][1] = v.value
ipv6_recv_bytes.clear()
if keys: if ipv6_throughput:
# more than 80 chars, sadly. # more than 80 chars, sadly.
print("\n%-6s %-12s %-32s %-32s %6s %6s" % ("PID", "COMM", print("\n%-6s %-12s %-32s %-32s %6s %6s" % ("PID", "COMM",
"LADDR6", "RADDR6", "RX_KB", "TX_KB")) "LADDR6", "RADDR6", "RX_KB", "TX_KB"))
# output # output
for k, v in reversed(sorted(keys.items(), key=lambda keys: keys[1].value)): for k, (send_bytes, recv_bytes) in sorted(ipv6_throughput.items(),
send_kbytes = 0 key=lambda kv: sum(kv[1]),
if k in ipv6_send_bytes: reverse=True):
send_kbytes = int(ipv6_send_bytes[k].value / 1024)
recv_kbytes = 0
if k in ipv6_recv_bytes:
recv_kbytes = int(ipv6_recv_bytes[k].value / 1024)
print("%-6d %-12.12s %-32s %-32s %6d %6d" % (k.pid, print("%-6d %-12.12s %-32s %-32s %6d %6d" % (k.pid,
pid_to_comm(k.pid), pid_to_comm(k.pid),
inet_ntop(AF_INET6, pack("QQ", k.saddr0, k.saddr1)) + ":" + k.laddr + ":" + str(k.lport),
str(k.lport), k.daddr + ":" + str(k.dport),
inet_ntop(AF_INET6, pack("QQ", k.daddr0, k.daddr1)) + ":" + int(recv_bytes / 1024), int(send_bytes / 1024)))
str(k.dport),
recv_kbytes, send_kbytes))
ipv6_send_bytes.clear()
ipv6_recv_bytes.clear()
i += 1 i += 1
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment