enhance tools/tcpaccept (#2254)
- add option `-T': include time column on output (HH:MM:SS)
- add option `-P PORT': only trace port(s) specified
- add RPORT colume on output
diff --git a/tools/tcpaccept.py b/tools/tcpaccept.py
index f606b73..169b0f3 100755
--- a/tools/tcpaccept.py
+++ b/tools/tcpaccept.py
@@ -4,7 +4,7 @@
# tcpaccept Trace TCP accept()s.
# For Linux, uses BCC, eBPF. Embedded C.
#
-# USAGE: tcpaccept [-h] [-t] [-p PID]
+# USAGE: tcpaccept [-h] [-T] [-t] [-p PID] [-P PORTS]
#
# This uses dynamic tracing of the kernel inet_csk_accept() socket function
# (from tcp_prot.accept), and will need to be modified to match kernel changes.
@@ -21,21 +21,27 @@
from struct import pack
import argparse
from bcc.utils import printb
+from time import strftime
# arguments
examples = """examples:
./tcpaccept # trace all TCP accept()s
./tcpaccept -t # include timestamps
+ ./tcpaccept -P 80,81 # only trace port 80 and 81
./tcpaccept -p 181 # only trace PID 181
"""
parser = argparse.ArgumentParser(
description="Trace TCP accepts",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog=examples)
+parser.add_argument("-T", "--time", action="store_true",
+ help="include time column on output (HH:MM:SS)")
parser.add_argument("-t", "--timestamp", action="store_true",
help="include timestamp on output")
parser.add_argument("-p", "--pid",
help="trace this PID only")
+parser.add_argument("-P", "--port",
+ help="comma-separated list of local ports to trace")
parser.add_argument("--ebpf", action="store_true",
help=argparse.SUPPRESS)
args = parser.parse_args()
@@ -55,6 +61,7 @@
u32 daddr;
u64 ip;
u16 lport;
+ u16 dport;
char task[TASK_COMM_LEN];
};
BPF_PERF_OUTPUT(ipv4_events);
@@ -66,6 +73,7 @@
unsigned __int128 daddr;
u64 ip;
u16 lport;
+ u16 dport;
char task[TASK_COMM_LEN];
};
BPF_PERF_OUTPUT(ipv6_events);
@@ -126,9 +134,13 @@
return 0;
// pull in details
- u16 family = 0, lport = 0;
+ u16 family = 0, lport = 0, dport;
family = newsk->__sk_common.skc_family;
lport = newsk->__sk_common.skc_num;
+ dport = newsk->__sk_common.skc_dport;
+ dport = ntohs(dport);
+
+ ##FILTER_PORT##
if (family == AF_INET) {
struct ipv4_data_t data4 = {.pid = pid, .ip = 4};
@@ -136,6 +148,7 @@
data4.saddr = newsk->__sk_common.skc_rcv_saddr;
data4.daddr = newsk->__sk_common.skc_daddr;
data4.lport = lport;
+ data4.dport = dport;
bpf_get_current_comm(&data4.task, sizeof(data4.task));
ipv4_events.perf_submit(ctx, &data4, sizeof(data4));
@@ -147,6 +160,7 @@
bpf_probe_read(&data6.daddr, sizeof(data6.daddr),
&newsk->__sk_common.skc_v6_daddr.in6_u.u6_addr32);
data6.lport = lport;
+ data6.dport = dport;
bpf_get_current_comm(&data6.task, sizeof(data6.task));
ipv6_events.perf_submit(ctx, &data6, sizeof(data6));
}
@@ -168,9 +182,12 @@
##FILTER_PID##
// pull in details
- u16 family = 0, lport = 0;
+ u16 family = 0, lport = 0, dport;
family = args->family;
lport = args->sport;
+ dport = args->dport;
+
+ ##FILTER_PORT##
if (family == AF_INET) {
struct ipv4_data_t data4 = {.pid = pid, .ip = 4};
@@ -178,6 +195,7 @@
__builtin_memcpy(&data4.saddr, args->saddr, sizeof(data4.saddr));
__builtin_memcpy(&data4.daddr, args->daddr, sizeof(data4.daddr));
data4.lport = lport;
+ data4.dport = dport;
bpf_get_current_comm(&data4.task, sizeof(data4.task));
ipv4_events.perf_submit(args, &data4, sizeof(data4));
} else if (family == AF_INET6) {
@@ -186,6 +204,7 @@
__builtin_memcpy(&data6.saddr, args->saddr, sizeof(data6.saddr));
__builtin_memcpy(&data6.daddr, args->daddr, sizeof(data6.daddr));
data6.lport = lport;
+ data6.dport = dport;
bpf_get_current_comm(&data6.task, sizeof(data6.task));
ipv6_events.perf_submit(args, &data6, sizeof(data6));
}
@@ -207,35 +226,48 @@
'if (pid != %s) { return 0; }' % args.pid)
else:
bpf_text = bpf_text.replace('##FILTER_PID##', '')
+if args.port:
+ lports = [int(lport) for lport in args.port.split(',')]
+ lports_if = ' && '.join(['lport != %d' % lport for lport in lports])
+ bpf_text = bpf_text.replace('##FILTER_PORT##',
+ 'if (%s) { return 0; }' % lports_if)
if debug or args.ebpf:
print(bpf_text)
if args.ebpf:
exit()
+bpf_text = bpf_text.replace('##FILTER_PORT##', '')
+
# process event
def print_ipv4_event(cpu, data, size):
event = b["ipv4_events"].event(data)
global start_ts
+ if args.time:
+ print("%-9s" % strftime("%H:%M:%S"), end="")
if args.timestamp:
if start_ts == 0:
start_ts = event.ts_us
print("%-9.3f" % ((float(event.ts_us) - start_ts) / 1000000), end="")
- printb(b"%-6d %-12.12s %-2d %-16s %-16s %-4d" % (event.pid,
+ printb(b"%-7d %-12.12s %-2d %-16s %-5d %-16s %-5d" % (event.pid,
event.task, event.ip,
inet_ntop(AF_INET, pack("I", event.daddr)).encode(),
+ event.dport,
inet_ntop(AF_INET, pack("I", event.saddr)).encode(),
event.lport))
def print_ipv6_event(cpu, data, size):
event = b["ipv6_events"].event(data)
global start_ts
+ if args.time:
+ print("%-9s" % strftime("%H:%M:%S"), end="")
if args.timestamp:
if start_ts == 0:
start_ts = event.ts_us
print("%-9.3f" % ((float(event.ts_us) - start_ts) / 1000000), end="")
- printb(b"%-6d %-12.12s %-2d %-16s %-16s %-4d" % (event.pid,
+ printb(b"%-7d %-12.12s %-2d %-16s %-5d %-16s %-5d" % (event.pid,
event.task, event.ip,
inet_ntop(AF_INET6, event.daddr).encode(),
+ event.dport,
inet_ntop(AF_INET6, event.saddr).encode(),
event.lport))
@@ -243,10 +275,12 @@
b = BPF(text=bpf_text)
# header
+if args.time:
+ print("%-9s" % ("TIME"), end="")
if args.timestamp:
print("%-9s" % ("TIME(s)"), end="")
-print("%-6s %-12s %-2s %-16s %-16s %-4s" % ("PID", "COMM", "IP", "RADDR",
- "LADDR", "LPORT"))
+print("%-7s %-12s %-2s %-16s %-5s %-16s %-5s" % ("PID", "COMM", "IP", "RADDR",
+ "RPORT", "LADDR", "LPORT"))
start_ts = 0