From 04893e3bb1c03a97f6ea3835986abe6608062f6a Mon Sep 17 00:00:00 2001 From: Hariharan Ananthakrishnan <5103173+hariharan-a@users.noreply.github.com> Date: Thu, 12 Aug 2021 05:55:21 -0700 Subject: [PATCH] Added IPv4/IPv6 filter support for tcp trace tools (#3565) * Added IPv4/IPv6 filter support for tcp trace tools * Fixed a typo * Added usage for TCP syn backlog * Fixed a typo * Fixed a typo * Added man support for IPv4/IPv6 family filters --- man/man8/tcpaccept.8 | 16 ++++++++++++- man/man8/tcpconnect.8 | 16 ++++++++++++- man/man8/tcpconnlat.8 | 16 ++++++++++++- man/man8/tcpdrop.8 | 20 +++++++++++++++- man/man8/tcplife.8 | 16 ++++++++++++- man/man8/tcpretrans.8 | 18 +++++++++++++-- man/man8/tcprtt.8 | 16 ++++++++++++- man/man8/tcpstates.8 | 16 ++++++++++++- man/man8/tcpsynbl.8 | 20 +++++++++++++++- man/man8/tcptop.8 | 16 ++++++++++++- man/man8/tcptracer.8 | 16 ++++++++++++- tools/tcpaccept.py | 19 ++++++++++++++- tools/tcpaccept_example.txt | 8 +++++-- tools/tcpconnect.py | 18 ++++++++++++++- tools/tcpconnect_example.txt | 8 +++++-- tools/tcpconnlat.py | 29 +++++++++++++++++++---- tools/tcpconnlat_example.txt | 6 ++++- tools/tcpdrop.py | 19 ++++++++++++++- tools/tcpdrop_example.txt | 6 ++++- tools/tcplife.py | 21 ++++++++++++++++- tools/tcplife_example.txt | 6 ++++- tools/tcpretrans.py | 22 ++++++++++++++++-- tools/tcpretrans_example.txt | 6 ++++- tools/tcprtt.py | 20 +++++++++++++++- tools/tcprtt_example.txt | 5 ++++ tools/tcpstates.py | 23 +++++++++++++++--- tools/tcpstates_example.txt | 6 ++++- tools/tcpsynbl.py | 36 +++++++++++++++++++++++++---- tools/tcpsynbl_example.txt | 17 ++++++++++++++ tools/tcptop.py | 20 +++++++++++++++- tools/tcptop_example.txt | 6 ++++- tools/tcptracer.py | 45 +++++++++++++++++++++++++++++++----- 32 files changed, 483 insertions(+), 49 deletions(-) diff --git a/man/man8/tcpaccept.8 b/man/man8/tcpaccept.8 index 603a5ca4..05b79693 100644 --- a/man/man8/tcpaccept.8 +++ b/man/man8/tcpaccept.8 @@ -2,7 +2,7 @@ .SH NAME tcpaccept \- Trace TCP passive connections (accept()). Uses Linux eBPF/bcc. .SH SYNOPSIS -.B tcpaccept [\-h] [\-T] [\-t] [\-p PID] [\-P PORTS] [\-\-cgroupmap MAPPATH] [\-\-mntnsmap MAPPATH] +.B tcpaccept [\-h] [\-T] [\-t] [\-p PID] [\-P PORTS] [\-4 | \-6] [\-\-cgroupmap MAPPATH] [\-\-mntnsmap MAPPATH] .SH DESCRIPTION This tool traces passive TCP connections (eg, via an accept() syscall; connect() are active connections). This can be useful for general @@ -34,6 +34,12 @@ Trace this process ID only (filtered in-kernel). \-P PORTS Comma-separated list of local ports to trace (filtered in-kernel). .TP +\-4 +Trace IPv4 family only. +.TP +\-6 +Trace IPv6 family only. +.TP \-\-cgroupmap MAPPATH Trace cgroups in this BPF map only (filtered in-kernel). .TP @@ -57,6 +63,14 @@ Trace PID 181 only: # .B tcpaccept \-p 181 .TP +Trace IPv4 family only: +# +.B tcpaccept \-4 +.TP +Trace IPv6 family only: +# +.B tcpaccept \-6 +.TP Trace a set of cgroups only (see special_filtering.md from bcc sources for more details): # .B tcpaccept \-\-cgroupmap /sys/fs/bpf/test01 diff --git a/man/man8/tcpconnect.8 b/man/man8/tcpconnect.8 index 55105709..0ea84686 100644 --- a/man/man8/tcpconnect.8 +++ b/man/man8/tcpconnect.8 @@ -2,7 +2,7 @@ .SH NAME tcpconnect \- Trace TCP active connections (connect()). Uses Linux eBPF/bcc. .SH SYNOPSIS -.B tcpconnect [\-h] [\-c] [\-t] [\-p PID] [-P PORT] [\-L] [-u UID] [-U] [\-\-cgroupmap MAPPATH] [\-\-mntnsmap MAPPATH] [\-d] +.B tcpconnect [\-h] [\-c] [\-t] [\-p PID] [-P PORT] [\-4 | \-6] [\-L] [-u UID] [-U] [\-\-cgroupmap MAPPATH] [\-\-mntnsmap MAPPATH] [\-d] .SH DESCRIPTION This tool traces active TCP connections (eg, via a connect() syscall; accept() are passive connections). This can be useful for general @@ -43,6 +43,12 @@ Trace this process ID only (filtered in-kernel). \-P PORT Comma-separated list of destination ports to trace (filtered in-kernel). .TP +\-4 +Trace IPv4 family only. +.TP +\-6 +Trace IPv6 family only. +.TP \-L Include a LPORT column. .TP @@ -99,6 +105,14 @@ Trace ports 80 and 81 only: # .B tcpconnect \-P 80,81 .TP +Trace IPv4 family only: +# +.B tcpconnect -4 +.TP +Trace IPv6 family only: +# +.B tcpconnect -6 +.TP Trace all TCP connects, and include LPORT: # .B tcpconnect \-L diff --git a/man/man8/tcpconnlat.8 b/man/man8/tcpconnlat.8 index 9c810071..84762b45 100644 --- a/man/man8/tcpconnlat.8 +++ b/man/man8/tcpconnlat.8 @@ -2,7 +2,7 @@ .SH NAME tcpconnlat \- Trace TCP active connection latency. Uses Linux eBPF/bcc. .SH SYNOPSIS -.B tcpconnlat [\-h] [\-t] [\-p PID] [\-L] [-v] [min_ms] +.B tcpconnlat [\-h] [\-t] [\-p PID] [\-L] [\-4 | \-6] [-v] [min_ms] .SH DESCRIPTION This tool traces active TCP connections (eg, via a connect() syscall), and shows the latency (time) for the connection @@ -34,6 +34,12 @@ Trace this process ID only (filtered in-kernel). \-L Include a LPORT column. .TP +\-4 +Trace IPv4 family only. +.TP +\-6 +Trace IPv6 family only. +.TP \-v Print the resulting BPF program, for debugging purposes. .TP @@ -57,6 +63,14 @@ Trace connects, and include LPORT: # .B tcpconnlat \-L .TP +Trace IPv4 family only: +# +.B tcpconnlat \-4 +.TP +Trace IPv6 family only: +# +.B tcpconnlat \-6 +.TP Trace connects with latency longer than 10 ms: # .B tcpconnlat 10 diff --git a/man/man8/tcpdrop.8 b/man/man8/tcpdrop.8 index 12806472..c9b777b3 100644 --- a/man/man8/tcpdrop.8 +++ b/man/man8/tcpdrop.8 @@ -2,7 +2,7 @@ .SH NAME tcpdrop \- Trace kernel-based TCP packet drops with details. Uses Linux eBPF/bcc. .SH SYNOPSIS -.B tcpdrop [\-h] +.B tcpdrop [\-4 | \-6] [\-h] .SH DESCRIPTION This tool traces TCP packets or segments that were dropped by the kernel, and shows details from the IP and TCP headers, the socket state, and the @@ -17,9 +17,27 @@ Since this uses BPF, only the root user can use this tool. CONFIG_BPF and bcc. .SH OPTIONS .TP +\-4 +Trace IPv4 family only. +.TP +\-6 +Trace IPv6 family only. +.TP \-h Print usage message. +.SH EXAMPLES +.TP +Trace kernel-based TCP packet drops with details: +# .B tcpdrop +.TP +Trace IPv4 family only: +# +.B tcpdrop \-4 +.TP +Trace IPv6 family only: +# +.B tcpdrop \-6 .SH FIELDS .TP TIME diff --git a/man/man8/tcplife.8 b/man/man8/tcplife.8 index a2419c61..5fb4c283 100644 --- a/man/man8/tcplife.8 +++ b/man/man8/tcplife.8 @@ -2,7 +2,7 @@ .SH NAME tcplife \- Trace TCP sessions and summarize lifespan. Uses Linux eBPF/bcc. .SH SYNOPSIS -.B tcplife [\-h] [\-T] [\-t] [\-w] [\-s] [\-p PID] [\-D PORTS] [\-L PORTS] +.B tcplife [\-h] [\-T] [\-t] [\-w] [\-s] [\-p PID] [\-D PORTS] [\-L PORTS] [\-4 | \-6] .SH DESCRIPTION This tool traces TCP sessions that open and close while tracing, and prints a line of output to summarize each one. This includes the IP addresses, ports, @@ -43,6 +43,12 @@ Comma-separated list of local ports to trace (filtered in-kernel). .TP \-D PORTS Comma-separated list of destination ports to trace (filtered in-kernel). +.TP +\-4 +Trace IPv4 family only. +.TP +\-6 +Trace IPv6 family only. .SH EXAMPLES .TP Trace all TCP sessions, and summarize lifespan and throughput: @@ -64,6 +70,14 @@ Trace connections to local ports 80 and 81 only: Trace connections to remote port 80 only: # .B tcplife \-D 80 +.TP +Trace IPv4 family only: +# +.B tcplife \-4 +.TP +Trace IPv6 family only: +# +.B tcplife \-6 .SH FIELDS .TP TIME diff --git a/man/man8/tcpretrans.8 b/man/man8/tcpretrans.8 index 0ac82afa..ea00ac7f 100644 --- a/man/man8/tcpretrans.8 +++ b/man/man8/tcpretrans.8 @@ -2,7 +2,7 @@ .SH NAME tcpretrans \- Trace or count TCP retransmits and TLPs. Uses Linux eBPF/bcc. .SH SYNOPSIS -.B tcpretrans [\-h] [\-l] [\-c] +.B tcpretrans [\-h] [\-l] [\-c] [\-4 | \-6] .SH DESCRIPTION This traces TCP retransmits, showing address, port, and TCP state information, and sometimes the PID (although usually not, since retransmits are usually @@ -29,7 +29,13 @@ Include tail loss probe attempts (in some cases the kernel may not complete the TLP send). .TP \-c -Count occurring retransmits per flow. +Count occurring retransmits per flow. +.TP +\-4 +Trace IPv4 family only. +.TP +\-6 +Trace IPv6 family only. .SH EXAMPLES .TP Trace TCP retransmits: @@ -39,6 +45,14 @@ Trace TCP retransmits: Trace TCP retransmits and TLP attempts: # .B tcpretrans \-l +.TP +Trace IPv4 family only: +# +.B tcpretrans \-4 +.TP +Trace IPv6 family only: +# +.B tcpretrans \-6 .SH FIELDS .TP TIME diff --git a/man/man8/tcprtt.8 b/man/man8/tcprtt.8 index f82ba6cc..1ed32d6e 100644 --- a/man/man8/tcprtt.8 +++ b/man/man8/tcprtt.8 @@ -2,7 +2,7 @@ .SH NAME tcprtt \- Trace TCP RTT of established connections. Uses Linux eBPF/bcc. .SH SYNOPSIS -.B tcprtt [\-h] [\-T] [\-D] [\-m] [\-i INTERVAL] [\-d DURATION] [\-b] [\-B] [\-e] +.B tcprtt [\-h] [\-T] [\-D] [\-m] [\-i INTERVAL] [\-d DURATION] [\-b] [\-B] [\-e] [\-4 | \-6] .SH DESCRIPTION This tool traces established connections RTT(round-trip time) to analyze the quality of network. This can be useful for general troubleshooting to @@ -51,6 +51,12 @@ Show sockets histogram by remote address. .TP \-e Show extension summary(average). +.TP +\-4 +Trace IPv4 family only. +.TP +\-6 +Trace IPv6 family only. .SH EXAMPLES .TP Trace TCP RTT and print 1 second summaries, 10 times: @@ -68,6 +74,14 @@ Only trace TCP RTT for remote address 192.168.1.100 and remote port 80: Trace local port and show a breakdown of remote hosts RTT: # .B tcprtt \-i 3 --lport 80 --byraddr +.TP +Trace IPv4 family only: +# +.B tcprtt \-4 +.TP +Trace IPv6 family only: +# +.B tcprtt \-6 .SH OVERHEAD This traces the kernel tcp_rcv_established function and collects TCP RTT. The rate of this depends on your server application. If it is a web or proxy server diff --git a/man/man8/tcpstates.8 b/man/man8/tcpstates.8 index 26c7a8a1..57c40a83 100644 --- a/man/man8/tcpstates.8 +++ b/man/man8/tcpstates.8 @@ -2,7 +2,7 @@ .SH NAME tcpstates \- Trace TCP session state changes with durations. Uses Linux eBPF/bcc. .SH SYNOPSIS -.B tcpstates [\-h] [\-T] [\-t] [\-w] [\-s] [\-D PORTS] [\-L PORTS] [\-Y] +.B tcpstates [\-h] [\-T] [\-t] [\-w] [\-s] [\-D PORTS] [\-L PORTS] [\-Y] [\-4 | \-6] .SH DESCRIPTION This tool traces TCP session state changes while tracing, and prints details including the duration in each state. This can help explain the latency of @@ -44,6 +44,12 @@ Comma-separated list of destination ports to trace (filtered in-kernel). .TP \-Y Log session state changes to the systemd journal. +.TP +\-4 +Trace IPv4 family only. +.TP +\-6 +Trace IPv6 family only. .SH EXAMPLES .TP Trace all TCP sessions, and show all state changes: @@ -61,6 +67,14 @@ Trace connections to local ports 80 and 81 only: Trace connections to remote port 80 only: # .B tcpstates \-D 80 +.TP +Trace IPv4 family only: +# +.B tcpstates -4 +.TP +Trace IPv6 family only: +# +.B tcpstates -6 .SH FIELDS .TP TIME diff --git a/man/man8/tcpsynbl.8 b/man/man8/tcpsynbl.8 index 4dd38c8a..8557af2b 100644 --- a/man/man8/tcpsynbl.8 +++ b/man/man8/tcpsynbl.8 @@ -2,7 +2,7 @@ .SH NAME tcpsynbl \- Show the TCP SYN backlog as a histogram. Uses BCC/eBPF. .SH SYNOPSIS -.B tcpsynbl +.B tcpsynbl [\-4 | \-6] .SH DESCRIPTION This tool shows the TCP SYN backlog size during SYN arrival as a histogram. This lets you see how close your applications are to hitting the backlog limit @@ -17,11 +17,29 @@ change in future kernels, this tool may need maintenance to keep working. Since this uses BPF, only the root user can use this tool. .SH REQUIREMENTS CONFIG_BPF and BCC. +.SH OPTIONS +.TP +\-h +Print usage message. +.TP +\-4 +Trace IPv4 family only. +.TP +\-6 +Trace IPv6 family only. .SH EXAMPLES .TP Show the TCP SYN backlog as a histogram. # .B tcpsynbl +.TP +Trace IPv4 family only: +# +.B tcpsynbl -4 +.TP +Trace IPv6 family only: +# +.B tcpsynbl -6 .SH FIELDS .TP backlog diff --git a/man/man8/tcptop.8 b/man/man8/tcptop.8 index e636f456..f4f1c3d7 100644 --- a/man/man8/tcptop.8 +++ b/man/man8/tcptop.8 @@ -3,7 +3,7 @@ tcptop \- Summarize TCP send/recv throughput by host. Top for TCP. .SH SYNOPSIS .B tcptop [\-h] [\-C] [\-S] [\-p PID] [\-\-cgroupmap MAPPATH] - [--mntnsmap MAPPATH] [interval] [count] + [--mntnsmap MAPPATH] [interval] [count] [\-4 | \-6] .SH DESCRIPTION This is top for TCP sessions. @@ -47,6 +47,12 @@ Interval between updates, seconds (default 1). .TP count Number of interval summaries (default is many). +.TP +\-4 +Trace IPv4 family only. +.TP +\-6 +Trace IPv6 family only. .SH EXAMPLES .TP Summarize TCP throughput by active sessions, 1 second refresh: @@ -64,6 +70,14 @@ Trace PID 181 only, and don't clear the screen: Trace a set of cgroups only (see special_filtering.md from bcc sources for more details): # .B tcptop \-\-cgroupmap /sys/fs/bpf/test01 +.TP +Trace IPv4 family only: +# +.B tcptop \-4 +.TP +Trace IPv6 family only: +# +.B tcptop \-6 .SH FIELDS .TP loadavg: diff --git a/man/man8/tcptracer.8 b/man/man8/tcptracer.8 index d2346c77..59240f4b 100644 --- a/man/man8/tcptracer.8 +++ b/man/man8/tcptracer.8 @@ -2,7 +2,7 @@ .SH NAME tcptracer \- Trace TCP established connections. Uses Linux eBPF/bcc. .SH SYNOPSIS -.B tcptracer [\-h] [\-v] [\-p PID] [\-N NETNS] [\-\-cgroupmap MAPPATH] [--mntnsmap MAPPATH] +.B tcptracer [\-h] [\-v] [\-p PID] [\-N NETNS] [\-\-cgroupmap MAPPATH] [--mntnsmap MAPPATH] [\-4 | \-6] .SH DESCRIPTION This tool traces established TCP connections that open and close while tracing, and prints a line of output per connect, accept and close events. This includes @@ -34,6 +34,12 @@ Trace cgroups in this BPF map only (filtered in-kernel). .TP \-\-mntnsmap MAPPATH Trace mount namespaces in the map (filtered in-kernel). +.TP +\-4 +Trace IPv4 family only. +.TP +\-6 +Trace IPv6 family only. .SH EXAMPLES .TP Trace all TCP established connections: @@ -55,6 +61,14 @@ Trace connections in network namespace 4026531969 only: Trace a set of cgroups only (see special_filtering.md from bcc sources for more details): # .B tcptracer \-\-cgroupmap /sys/fs/bpf/test01 +.TP +Trace IPv4 family only: +# +.B tcptracer -4 +.TP +Trace IPv6 family only: +# +.B tcptracer -6 .SH FIELDS .TP TYPE diff --git a/tools/tcpaccept.py b/tools/tcpaccept.py index 1a5f1c7b..d3e44143 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] [-t] [-p PID] [-P PORTS] +# USAGE: tcpaccept [-h] [-T] [-t] [-p PID] [-P PORTS] [-4 | -6] # # 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. @@ -32,6 +32,8 @@ examples = """examples: ./tcpaccept -p 181 # only trace PID 181 ./tcpaccept --cgroupmap mappath # only trace cgroups in this BPF map ./tcpaccept --mntnsmap mappath # only trace mount namespaces in the map + ./tcpaccept -4 # trace IPv4 family + ./tcpaccept -6 # trace IPv6 family """ parser = argparse.ArgumentParser( description="Trace TCP accepts", @@ -45,6 +47,11 @@ parser.add_argument("-p", "--pid", help="trace this PID only") parser.add_argument("-P", "--port", help="comma-separated list of local ports to trace") +group = parser.add_mutually_exclusive_group() +group.add_argument("-4", "--ipv4", action="store_true", + help="trace IPv4 family only") +group.add_argument("-6", "--ipv6", action="store_true", + help="trace IPv6 family only") parser.add_argument("--cgroupmap", help="trace cgroups in this BPF map only") parser.add_argument("--mntnsmap", @@ -152,6 +159,8 @@ int kretprobe__inet_csk_accept(struct pt_regs *ctx) dport = newsk->__sk_common.skc_dport; dport = ntohs(dport); + ##FILTER_FAMILY## + ##FILTER_PORT## if (family == AF_INET) { @@ -195,6 +204,13 @@ if args.port: lports_if = ' && '.join(['lport != %d' % lport for lport in lports]) bpf_text = bpf_text.replace('##FILTER_PORT##', 'if (%s) { return 0; }' % lports_if) +if args.ipv4: + bpf_text = bpf_text.replace('##FILTER_FAMILY##', + 'if (family != AF_INET) { return 0; }') +elif args.ipv6: + bpf_text = bpf_text.replace('##FILTER_FAMILY##', + 'if (family != AF_INET6) { return 0; }') + bpf_text = filter_by_containers(args) + bpf_text if debug or args.ebpf: print(bpf_text) @@ -202,6 +218,7 @@ if debug or args.ebpf: exit() bpf_text = bpf_text.replace('##FILTER_PORT##', '') +bpf_text = bpf_text.replace('##FILTER_FAMILY##', '') # process event def print_ipv4_event(cpu, data, size): diff --git a/tools/tcpaccept_example.txt b/tools/tcpaccept_example.txt index 93815655..24567904 100644 --- a/tools/tcpaccept_example.txt +++ b/tools/tcpaccept_example.txt @@ -44,7 +44,7 @@ For more details, see docs/special_filtering.md USAGE message: # ./tcpaccept -h -usage: tcpaccept.py [-h] [-T] [-t] [-p PID] [-P PORT] [--cgroupmap CGROUPMAP] +usage: tcpaccept.py [-h] [-T] [-t] [-p PID] [-P PORT] [-4 | -6] [--cgroupmap CGROUPMAP] Trace TCP accepts @@ -54,6 +54,8 @@ optional arguments: -t, --timestamp include timestamp on output -p PID, --pid PID trace this PID only -P PORT, --port PORT comma-separated list of local ports to trace + -4, --ipv4 trace IPv4 family only + -6, --ipv6 trace IPv6 family only --cgroupmap CGROUPMAP trace cgroups in this BPF map only @@ -63,4 +65,6 @@ examples: ./tcpaccept -P 80,81 # only trace port 80 and 81 ./tcpaccept -p 181 # only trace PID 181 ./tcpaccept --cgroupmap mappath # only trace cgroups in this BPF map - ./tcpaccept --mntnsmap mappath # only trace mount namespaces in the map \ No newline at end of file + ./tcpaccept --mntnsmap mappath # only trace mount namespaces in the map + ./tcpaccept -4 # trace IPv4 family only + ./tcpaccept -6 # trace IPv6 family only \ No newline at end of file diff --git a/tools/tcpconnect.py b/tools/tcpconnect.py index 0d204ea5..8b49c70a 100755 --- a/tools/tcpconnect.py +++ b/tools/tcpconnect.py @@ -4,7 +4,7 @@ # tcpconnect Trace TCP connect()s. # For Linux, uses BCC, eBPF. Embedded C. # -# USAGE: tcpconnect [-h] [-c] [-t] [-p PID] [-P PORT [PORT ...]] +# USAGE: tcpconnect [-h] [-c] [-t] [-p PID] [-P PORT [PORT ...]] [-4 | -6] # # All connection attempts are traced, even if they ultimately fail. # @@ -39,6 +39,8 @@ examples = """examples: ./tcpconnect -p 181 # only trace PID 181 ./tcpconnect -P 80 # only trace port 80 ./tcpconnect -P 80,81 # only trace port 80 and 81 + ./tcpconnect -4 # only trace IPv4 family + ./tcpconnect -6 # only trace IPv6 family ./tcpconnect -U # include UID ./tcpconnect -u 1000 # only trace UID 1000 ./tcpconnect -c # count connects per src ip and dest ip/port @@ -56,6 +58,11 @@ parser.add_argument("-p", "--pid", help="trace this PID only") parser.add_argument("-P", "--port", help="comma-separated list of destination ports to trace.") +group = parser.add_mutually_exclusive_group() +group.add_argument("-4", "--ipv4", action="store_true", + help="trace IPv4 family only") +group.add_argument("-6", "--ipv6", action="store_true", + help="trace IPv6 family only") parser.add_argument("-L", "--lport", action="store_true", help="include LPORT on output") parser.add_argument("-U", "--print-uid", action="store_true", @@ -171,6 +178,8 @@ static int trace_connect_return(struct pt_regs *ctx, short ipver) u16 dport = skp->__sk_common.skc_dport; FILTER_PORT + + FILTER_FAMILY if (ipver == 4) { IPV4_CODE @@ -335,6 +344,12 @@ if args.port: dports_if = ' && '.join(['dport != %d' % ntohs(dport) for dport in dports]) bpf_text = bpf_text.replace('FILTER_PORT', 'if (%s) { currsock.delete(&tid); return 0; }' % dports_if) +if args.ipv4: + bpf_text = bpf_text.replace('FILTER_FAMILY', + 'if (ipver != 4) { return 0; }') +elif args.ipv6: + bpf_text = bpf_text.replace('FILTER_FAMILY', + 'if (ipver != 6) { return 0; }') if args.uid: bpf_text = bpf_text.replace('FILTER_UID', 'if (uid != %s) { return 0; }' % args.uid) @@ -342,6 +357,7 @@ bpf_text = filter_by_containers(args) + bpf_text bpf_text = bpf_text.replace('FILTER_PID', '') bpf_text = bpf_text.replace('FILTER_PORT', '') +bpf_text = bpf_text.replace('FILTER_FAMILY', '') bpf_text = bpf_text.replace('FILTER_UID', '') if args.dns: diff --git a/tools/tcpconnect_example.txt b/tools/tcpconnect_example.txt index f2e6d72f..3f720c42 100644 --- a/tools/tcpconnect_example.txt +++ b/tools/tcpconnect_example.txt @@ -106,8 +106,8 @@ USAGE message: # ./tcpconnect -h -usage: tcpconnect.py [-h] [-t] [-p PID] [-P PORT] [-L] [-U] [-u UID] [-c] - [--cgroupmap CGROUPMAP] [--mntnsmap MNTNSMAP] [-d] +usage: tcpconnect.py [-h] [-t] [-p PID] [-P PORT] [-4 | -6] [-L] [-U] [-u UID] + [-c] [--cgroupmap CGROUPMAP] [--mntnsmap MNTNSMAP] [-d] Trace TCP connects @@ -116,6 +116,8 @@ optional arguments: -t, --timestamp include timestamp on output -p PID, --pid PID trace this PID only -P PORT, --port PORT comma-separated list of destination ports to trace. + -4, --ipv4 trace IPv4 family only + -6, --ipv6 trace IPv6 family only -L, --lport include LPORT on output -U, --print-uid include UID on output -u UID, --uid UID trace this UID only @@ -132,6 +134,8 @@ examples: ./tcpconnect -p 181 # only trace PID 181 ./tcpconnect -P 80 # only trace port 80 ./tcpconnect -P 80,81 # only trace port 80 and 81 + ./tcpconnect -4 # only trace IPv4 family + ./tcpconnect -6 # only trace IPv6 family ./tcpconnect -U # include UID ./tcpconnect -u 1000 # only trace UID 1000 ./tcpconnect -c # count connects per src ip and dest ip/port diff --git a/tools/tcpconnlat.py b/tools/tcpconnlat.py index f30b71d2..093f2676 100755 --- a/tools/tcpconnlat.py +++ b/tools/tcpconnlat.py @@ -4,7 +4,7 @@ # tcpconnlat Trace TCP active connection latency (connect). # For Linux, uses BCC, eBPF. Embedded C. # -# USAGE: tcpconnlat [-h] [-t] [-p PID] +# USAGE: tcpconnlat [-h] [-t] [-p PID] [-4 | -6] # # This uses dynamic tracing of kernel functions, and will need to be updated # to match kernel changes. @@ -40,6 +40,8 @@ examples = """examples: ./tcpconnlat -t # include timestamps ./tcpconnlat -p 181 # only trace PID 181 ./tcpconnlat -L # include LPORT while printing outputs + ./tcpconnlat -4 # trace IPv4 family only + ./tcpconnlat -6 # trace IPv6 family only """ parser = argparse.ArgumentParser( description="Trace TCP connects and show connection latency", @@ -51,6 +53,11 @@ parser.add_argument("-p", "--pid", help="trace this PID only") parser.add_argument("-L", "--lport", action="store_true", help="include LPORT on output") +group = parser.add_mutually_exclusive_group() +group.add_argument("-4", "--ipv4", action="store_true", + help="trace IPv4 family only") +group.add_argument("-6", "--ipv6", action="store_true", + help="trace IPv6 family only") parser.add_argument("duration_ms", nargs="?", default=0, type=positive_float, help="minimum duration to trace (ms)") @@ -202,8 +209,14 @@ if debug or args.verbose or args.ebpf: # initialize BPF b = BPF(text=bpf_text) -b.attach_kprobe(event="tcp_v4_connect", fn_name="trace_connect") -b.attach_kprobe(event="tcp_v6_connect", fn_name="trace_connect") +if args.ipv4: + b.attach_kprobe(event="tcp_v4_connect", fn_name="trace_connect") +elif args.ipv6: + b.attach_kprobe(event="tcp_v6_connect", fn_name="trace_connect") +else: + b.attach_kprobe(event="tcp_v4_connect", fn_name="trace_connect") + b.attach_kprobe(event="tcp_v6_connect", fn_name="trace_connect") + b.attach_kprobe(event="tcp_rcv_state_process", fn_name="trace_tcp_rcv_state_process") @@ -260,8 +273,14 @@ else: "SADDR", "DADDR", "DPORT", "LAT(ms)")) # read events -b["ipv4_events"].open_perf_buffer(print_ipv4_event) -b["ipv6_events"].open_perf_buffer(print_ipv6_event) +if args.ipv4: + b["ipv4_events"].open_perf_buffer(print_ipv4_event) +elif args.ipv6: + b["ipv6_events"].open_perf_buffer(print_ipv6_event) +else: + b["ipv4_events"].open_perf_buffer(print_ipv4_event) + b["ipv6_events"].open_perf_buffer(print_ipv6_event) + while 1: try: b.perf_buffer_poll() diff --git a/tools/tcpconnlat_example.txt b/tools/tcpconnlat_example.txt index 8ca2821b..fe05ca5c 100644 --- a/tools/tcpconnlat_example.txt +++ b/tools/tcpconnlat_example.txt @@ -34,7 +34,7 @@ if the response is a RST (port closed). USAGE message: # ./tcpconnlat -h -usage: tcpconnlat [-h] [-t] [-p PID] [-L] [-v] [duration_ms] +usage: tcpconnlat [-h] [-t] [-p PID] [-L] [-4 | -6] [-v] [duration_ms] Trace TCP connects and show connection latency @@ -46,6 +46,8 @@ optional arguments: -t, --timestamp include timestamp on output -p PID, --pid PID trace this PID only -L, --lport include LPORT on output + -4, --ipv4 trace IPv4 family only + -6 --ipv6 trace IPv6 family only -v, --verbose print the BPF program for debugging purposes examples: @@ -55,3 +57,5 @@ examples: ./tcpconnlat -t # include timestamps ./tcpconnlat -p 181 # only trace PID 181 ./tcpconnlat -L # include LPORT while printing outputs + ./tcpconnlat -4 # trace IPv4 family only + ./tcpconnlat -6 # trace IPv6 family only diff --git a/tools/tcpdrop.py b/tools/tcpdrop.py index 59dbf66c..4853f6ab 100755 --- a/tools/tcpdrop.py +++ b/tools/tcpdrop.py @@ -7,7 +7,7 @@ # This provides information such as packet details, socket state, and kernel # stack trace for packets/segments that were dropped via tcp_drop(). # -# USAGE: tcpdrop [-h] +# USAGE: tcpdrop [-4 | -6] [-h] # # This uses dynamic tracing of kernel functions, and will need to be updated # to match kernel changes. @@ -29,11 +29,18 @@ from bcc import tcp # arguments examples = """examples: ./tcpdrop # trace kernel TCP drops + ./tcpdrop -4 # trace IPv4 family only + ./tcpdrop -6 # trace IPv6 family only """ parser = argparse.ArgumentParser( description="Trace TCP drops by the kernel", formatter_class=argparse.RawDescriptionHelpFormatter, epilog=examples) +group = parser.add_mutually_exclusive_group() +group.add_argument("-4", "--ipv4", action="store_true", + help="trace IPv4 family only") +group.add_argument("-6", "--ipv6", action="store_true", + help="trace IPv6 family only") parser.add_argument("--ebpf", action="store_true", help=argparse.SUPPRESS) args = parser.parse_args() @@ -111,6 +118,8 @@ int trace_tcp_drop(struct pt_regs *ctx, struct sock *sk, struct sk_buff *skb) sport = ntohs(sport); dport = ntohs(dport); + FILTER_FAMILY + if (family == AF_INET) { struct ipv4_data_t data4 = {}; data4.pid = pid; @@ -151,6 +160,14 @@ if debug or args.ebpf: print(bpf_text) if args.ebpf: exit() +if args.ipv4: + bpf_text = bpf_text.replace('FILTER_FAMILY', + 'if (family != AF_INET) { return 0; }') +elif args.ipv6: + bpf_text = bpf_text.replace('FILTER_FAMILY', + 'if (family != AF_INET6) { return 0; }') +else: + bpf_text = bpf_text.replace('FILTER_FAMILY', '') # process event def print_ipv4_event(cpu, data, size): diff --git a/tools/tcpdrop_example.txt b/tools/tcpdrop_example.txt index 752ec4bf..2adbb6c0 100644 --- a/tools/tcpdrop_example.txt +++ b/tools/tcpdrop_example.txt @@ -61,12 +61,16 @@ remote end to do timer-based retransmits, hurting performance. USAGE: # ./tcpdrop.py -h -usage: tcpdrop.py [-h] +usage: tcpdrop.py [4 | -6] [-h] Trace TCP drops by the kernel optional arguments: + -4, --ipv4 trace IPv4 family only + -6, --ipv6 trace IPv6 family only -h, --help show this help message and exit examples: ./tcpdrop # trace kernel TCP drops + ./tcpdrop -4 # trace IPv4 family only + ./tcpdrop -6 # trace IPv6 family only diff --git a/tools/tcplife.py b/tools/tcplife.py index 9fe9804b..780385b4 100755 --- a/tools/tcplife.py +++ b/tools/tcplife.py @@ -4,7 +4,7 @@ # tcplife Trace the lifespan of TCP sessions and summarize. # For Linux, uses BCC, BPF. Embedded C. # -# USAGE: tcplife [-h] [-C] [-S] [-p PID] [interval [count]] +# USAGE: tcplife [-h] [-C] [-S] [-p PID] [-4 | -6] [interval [count]] # # This uses the sock:inet_sock_set_state tracepoint if it exists (added to # Linux 4.16, and replacing the earlier tcp:tcp_set_state), else it uses @@ -39,6 +39,8 @@ examples = """examples: ./tcplife -L 80 # only trace local port 80 ./tcplife -L 80,81 # only trace local ports 80 and 81 ./tcplife -D 80 # only trace remote port 80 + ./tcplife -4 # only trace IPv4 family + ./tcplife -6 # only trace IPv6 family """ parser = argparse.ArgumentParser( description="Trace the lifespan of TCP sessions and summarize", @@ -58,6 +60,11 @@ parser.add_argument("-L", "--localport", help="comma-separated list of local ports to trace.") parser.add_argument("-D", "--remoteport", help="comma-separated list of remote ports to trace.") +group = parser.add_mutually_exclusive_group() +group.add_argument("-4", "--ipv4", action="store_true", + help="trace IPv4 family only") +group.add_argument("-6", "--ipv6", action="store_true", + help="trace IPv6 family only") parser.add_argument("--ebpf", action="store_true", help=argparse.SUPPRESS) args = parser.parse_args() @@ -190,6 +197,8 @@ int kprobe__tcp_set_state(struct pt_regs *ctx, struct sock *sk, int state) tx_b = tp->bytes_acked; u16 family = sk->__sk_common.skc_family; + + FILTER_FAMILY if (family == AF_INET) { struct ipv4_data_t data4 = {}; @@ -309,6 +318,9 @@ TRACEPOINT_PROBE(sock, inet_sock_set_state) if (mep != 0) pid = mep->pid; FILTER_PID + + u16 family = args->family; + FILTER_FAMILY // get throughput stats. see tcp_get_info(). u64 rx_b = 0, tx_b = 0, sport = 0; @@ -380,9 +392,16 @@ if args.localport: lports_if = ' && '.join(['lport != %d' % lport for lport in lports]) bpf_text = bpf_text.replace('FILTER_LPORT', 'if (%s) { birth.delete(&sk); return 0; }' % lports_if) +if args.ipv4: + bpf_text = bpf_text.replace('FILTER_FAMILY', + 'if (family != AF_INET) { return 0; }') +elif args.ipv6: + bpf_text = bpf_text.replace('FILTER_FAMILY', + 'if (family != AF_INET6) { return 0; }') bpf_text = bpf_text.replace('FILTER_PID', '') bpf_text = bpf_text.replace('FILTER_DPORT', '') bpf_text = bpf_text.replace('FILTER_LPORT', '') +bpf_text = bpf_text.replace('FILTER_FAMILY', '') if debug or args.ebpf: print(bpf_text) diff --git a/tools/tcplife_example.txt b/tools/tcplife_example.txt index cbf44796..88c40df7 100644 --- a/tools/tcplife_example.txt +++ b/tools/tcplife_example.txt @@ -108,7 +108,7 @@ USAGE: # ./tcplife.py -h usage: tcplife.py [-h] [-T] [-t] [-w] [-s] [-p PID] [-L LOCALPORT] - [-D REMOTEPORT] + [-D REMOTEPORT] [-4 | -6] Trace the lifespan of TCP sessions and summarize @@ -123,6 +123,8 @@ optional arguments: comma-separated list of local ports to trace. -D REMOTEPORT, --remoteport REMOTEPORT comma-separated list of remote ports to trace. + -4, --ipv4 trace IPv4 family only + -6, --ipv6 trace IPv6 family only examples: ./tcplife # trace all TCP connect()s @@ -133,3 +135,5 @@ examples: ./tcplife -L 80 # only trace local port 80 ./tcplife -L 80,81 # only trace local ports 80 and 81 ./tcplife -D 80 # only trace remote port 80 + ./tcplife -4 # only trace IPv4 family + ./tcplife -6 # only trace IPv6 family diff --git a/tools/tcpretrans.py b/tools/tcpretrans.py index 7785d9b3..8e6247f7 100755 --- a/tools/tcpretrans.py +++ b/tools/tcpretrans.py @@ -4,7 +4,7 @@ # tcpretrans Trace or count TCP retransmits and TLPs. # For Linux, uses BCC, eBPF. Embedded C. # -# USAGE: tcpretrans [-c] [-h] [-l] +# USAGE: tcpretrans [-c] [-h] [-l] [-4 | -6] # # This uses dynamic tracing of kernel functions, and will need to be updated # to match kernel changes. @@ -27,6 +27,8 @@ from time import sleep examples = """examples: ./tcpretrans # trace TCP retransmits ./tcpretrans -l # include TLP attempts + ./tcpretrans -4 # trace IPv4 family only + ./tcpretrans -6 # trace IPv6 family only """ parser = argparse.ArgumentParser( description="Trace TCP retransmits", @@ -36,6 +38,11 @@ parser.add_argument("-l", "--lossprobe", action="store_true", help="include tail loss probe attempts") parser.add_argument("-c", "--count", action="store_true", help="count occurred retransmits per flow") +group = parser.add_mutually_exclusive_group() +group.add_argument("-4", "--ipv4", action="store_true", + help="trace IPv4 family only") +group.add_argument("-6", "--ipv6", action="store_true", + help="trace IPv6 family only") parser.add_argument("--ebpf", action="store_true", help=argparse.SUPPRESS) args = parser.parse_args() @@ -106,6 +113,8 @@ static int trace_event(struct pt_regs *ctx, struct sock *skp, int type) u16 dport = skp->__sk_common.skc_dport; char state = skp->__sk_common.skc_state; + FILTER_FAMILY + if (family == AF_INET) { IPV4_INIT IPV4_CORE @@ -145,6 +154,8 @@ TRACEPOINT_PROBE(tcp, tcp_retransmit_skb) char state = skp->__sk_common.skc_state; u16 family = skp->__sk_common.skc_family; + FILTER_FAMILY + if (family == AF_INET) { IPV4_CODE } else if (family == AF_INET6) { @@ -278,7 +289,14 @@ if args.lossprobe or not BPF.tracepoint_exists("tcp", "tcp_retransmit_skb"): bpf_text += bpf_text_kprobe_tlp if not BPF.tracepoint_exists("tcp", "tcp_retransmit_skb"): bpf_text += bpf_text_kprobe_retransmit - +if args.ipv4: + bpf_text = bpf_text.replace('FILTER_FAMILY', + 'if (family != AF_INET) { return 0; }') +elif args.ipv6: + bpf_text = bpf_text.replace('FILTER_FAMILY', + 'if (family != AF_INET6) { return 0; }') +else: + bpf_text = bpf_text.replace('FILTER_FAMILY', '') if debug or args.ebpf: print(bpf_text) if args.ebpf: diff --git a/tools/tcpretrans_example.txt b/tools/tcpretrans_example.txt index db634775..77fc12f8 100644 --- a/tools/tcpretrans_example.txt +++ b/tools/tcpretrans_example.txt @@ -62,7 +62,7 @@ responsible for clamping tcp performance. USAGE message: # ./tcpretrans -h -usage: tcpretrans [-h] [-l] +usage: tcpretrans [-h] [-l] [-4 | -6] Trace TCP retransmits @@ -70,7 +70,11 @@ optional arguments: -h, --help show this help message and exit -l, --lossprobe include tail loss probe attempts -c, --count count occurred retransmits per flow + -4, --ipv4 trace IPv4 family only + -6, --ipv6 trace IPv6 family only examples: ./tcpretrans # trace TCP retransmits ./tcpretrans -l # include TLP attempts + ./tcpretrans -4 # trace IPv4 family only + ./tcpretrans -6 # trace IPv6 family only diff --git a/tools/tcprtt.py b/tools/tcprtt.py index ac1b27d4..c5c3905a 100755 --- a/tools/tcprtt.py +++ b/tools/tcprtt.py @@ -5,6 +5,7 @@ # # USAGE: tcprtt [-h] [-T] [-D] [-m] [-i INTERVAL] [-d DURATION] # [-p LPORT] [-P RPORT] [-a LADDR] [-A RADDR] [-b] [-B] [-e] +# [-4 | -6] # # Copyright (c) 2020 zhenwei pi # Licensed under the Apache License, Version 2.0 (the "License") @@ -32,6 +33,8 @@ examples = """examples: ./tcprtt -B # show sockets histogram by remote address ./tcprtt -D # show debug bpf text ./tcprtt -e # show extension summary(average) + ./tcprtt -4 # trace only IPv4 family + ./tcprtt -6 # trace only IPv6 family """ parser = argparse.ArgumentParser( description="Summarize TCP RTT as a histogram", @@ -61,6 +64,11 @@ parser.add_argument("-e", "--extension", action="store_true", help="show extension summary(average)") parser.add_argument("-D", "--debug", action="store_true", help="print BPF program before starting (for debugging purposes)") +group = parser.add_mutually_exclusive_group() +group.add_argument("-4", "--ipv4", action="store_true", + help="trace IPv4 family only") +group.add_argument("-6", "--ipv6", action="store_true", + help="trace IPv6 family only") parser.add_argument("--ebpf", action="store_true", help=argparse.SUPPRESS) args = parser.parse_args() @@ -102,6 +110,7 @@ int trace_tcp_rcv(struct pt_regs *ctx, struct sock *sk, struct sk_buff *skb) u16 dport = 0; u32 saddr = 0; u32 daddr = 0; + u16 family = 0; /* for histogram */ sock_key_t key; @@ -113,11 +122,13 @@ int trace_tcp_rcv(struct pt_regs *ctx, struct sock *sk, struct sk_buff *skb) bpf_probe_read_kernel(&dport, sizeof(dport), (void *)&inet->inet_dport); bpf_probe_read_kernel(&saddr, sizeof(saddr), (void *)&inet->inet_saddr); bpf_probe_read_kernel(&daddr, sizeof(daddr), (void *)&inet->inet_daddr); + bpf_probe_read_kernel(&family, sizeof(family), (void *)&sk->__sk_common.skc_family); LPORTFILTER RPORTFILTER LADDRFILTER RADDRFILTER + FAMILYFILTER FACTOR @@ -162,7 +173,14 @@ if args.raddr: return 0;""" % struct.unpack("=I", socket.inet_aton(args.raddr))[0]) else: bpf_text = bpf_text.replace('RADDRFILTER', '') - +if args.ipv4: + bpf_text = bpf_text.replace('FAMILYFILTER', + 'if (family != AF_INET) { return 0; }') +elif args.ipv6: + bpf_text = bpf_text.replace('FAMILYFILTER', + 'if (family != AF_INET6) { return 0; }') +else: + bpf_text = bpf_text.replace('FAMILYFILTER', '') # show msecs or usecs[default] if args.milliseconds: bpf_text = bpf_text.replace('FACTOR', 'srtt /= 1000;') diff --git a/tools/tcprtt_example.txt b/tools/tcprtt_example.txt index fbfe18f6..afc1293c 100644 --- a/tools/tcprtt_example.txt +++ b/tools/tcprtt_example.txt @@ -144,6 +144,7 @@ Full USAGE: # ./tcprtt -h usage: tcprtt [-h] [-i INTERVAL] [-d DURATION] [-T] [-m] [-p LPORT] [-P RPORT] [-a LADDR] [-A RADDR] [-b] [-B] [-e] [-D] + [-4 | -6] Summarize TCP RTT as a histogram @@ -168,6 +169,8 @@ optional arguments: -e, --extension show extension summary(average) -D, --debug print BPF program before starting (for debugging purposes) + -4, --ipv4 trace IPv4 family only + -6, --ipv6 trace IPv6 family only examples: ./tcprtt # summarize TCP RTT @@ -181,3 +184,5 @@ examples: ./tcprtt -B # show sockets histogram by remote address ./tcprtt -D # show debug bpf text ./tcprtt -e # show extension summary(average) + ./tcprtt -4 # trace IPv4 family only + ./tcprtt -6 # trace IPv6 family only diff --git a/tools/tcpstates.py b/tools/tcpstates.py index ec5bb7b3..cb38c591 100755 --- a/tools/tcpstates.py +++ b/tools/tcpstates.py @@ -5,7 +5,7 @@ # tcpstates Trace the TCP session state changes with durations. # For Linux, uses BCC, BPF. Embedded C. # -# USAGE: tcpstates [-h] [-C] [-S] [interval [count]] +# USAGE: tcpstates [-h] [-C] [-S] [interval [count]] [-4 | -6] # # This uses the sock:inet_sock_set_state tracepoint, added to Linux 4.16. # Linux 4.16 also adds more state transitions so that they can be traced. @@ -34,6 +34,8 @@ examples = """examples: ./tcpstates -L 80 # only trace local port 80 ./tcpstates -L 80,81 # only trace local ports 80 and 81 ./tcpstates -D 80 # only trace remote port 80 + ./tcpstates -4 # trace IPv4 family only + ./tcpstates -6 # trace IPv6 family only """ parser = argparse.ArgumentParser( description="Trace TCP session state changes and durations", @@ -55,6 +57,11 @@ parser.add_argument("--ebpf", action="store_true", help=argparse.SUPPRESS) parser.add_argument("-Y", "--journal", action="store_true", help="log session state changes to the systemd journal") +group = parser.add_mutually_exclusive_group() +group.add_argument("-4", "--ipv4", action="store_true", + help="trace IPv4 family only") +group.add_argument("-6", "--ipv6", action="store_true", + help="trace IPv6 family only") args = parser.parse_args() debug = 0 @@ -126,7 +133,9 @@ TRACEPOINT_PROBE(sock, inet_sock_set_state) delta_us = 0; else delta_us = (bpf_ktime_get_ns() - *tsp) / 1000; - + u16 family = args->family; + FILTER_FAMILY + if (args->family == AF_INET) { struct ipv4_data_t data4 = { .span_us = delta_us, @@ -194,7 +203,8 @@ int kprobe__tcp_set_state(struct pt_regs *ctx, struct sock *sk, int state) delta_us = (bpf_ktime_get_ns() - *tsp) / 1000; u16 family = sk->__sk_common.skc_family; - + FILTER_FAMILY + if (family == AF_INET) { struct ipv4_data_t data4 = { .span_us = delta_us, @@ -258,6 +268,13 @@ if args.localport: lports_if = ' && '.join(['lport != %d' % lport for lport in lports]) bpf_text = bpf_text.replace('FILTER_LPORT', 'if (%s) { last.delete(&sk); return 0; }' % lports_if) +if args.ipv4: + bpf_text = bpf_text.replace('FILTER_FAMILY', + 'if (family != AF_INET) { return 0; }') +elif args.ipv6: + bpf_text = bpf_text.replace('FILTER_FAMILY', + 'if (family != AF_INET6) { return 0; }') +bpf_text = bpf_text.replace('FILTER_FAMILY', '') bpf_text = bpf_text.replace('FILTER_DPORT', '') bpf_text = bpf_text.replace('FILTER_LPORT', '') diff --git a/tools/tcpstates_example.txt b/tools/tcpstates_example.txt index e50012e7..5a7d543a 100644 --- a/tools/tcpstates_example.txt +++ b/tools/tcpstates_example.txt @@ -27,7 +27,7 @@ USAGE: # tcpstates -h usage: tcpstates.py [-h] [-T] [-t] [-w] [-s] [-L LOCALPORT] [-D REMOTEPORT] - [-Y] + [-Y] [-4 | -6] Trace TCP session state changes and durations @@ -42,6 +42,8 @@ optional arguments: -D REMOTEPORT, --remoteport REMOTEPORT comma-separated list of remote ports to trace. -Y, --journal log session state changes to the systemd journal + -4, --ipv4 trace IPv4 family only + -6, --ipv6 trace IPv6 family only examples: ./tcpstates # trace all TCP state changes @@ -53,3 +55,5 @@ examples: ./tcpstates -L 80 # only trace local port 80 ./tcpstates -L 80,81 # only trace local ports 80 and 81 ./tcpstates -D 80 # only trace remote port 80 + ./tcpstates -4 # trace IPv4 family only + ./tcpstates -6 # trace IPv6 family only diff --git a/tools/tcpsynbl.py b/tools/tcpsynbl.py index 93cef4b7..dc85abe7 100755 --- a/tools/tcpsynbl.py +++ b/tools/tcpsynbl.py @@ -4,6 +4,8 @@ # tcpsynbl Show TCP SYN backlog. # For Linux, uses BCC, eBPF. Embedded C. # +# USAGE: tcpsynbl [-4 | -6] [-h] +# # Copyright (c) 2019 Brendan Gregg. # Licensed under the Apache License, Version 2.0 (the "License"). # This was originally created for the BPF Performance Tools book @@ -13,11 +15,12 @@ # 03-Jul-2019 Brendan Gregg Ported from bpftrace to BCC. from __future__ import print_function +import argparse from bcc import BPF from time import sleep # load BPF program -b = BPF(text=""" +bpf_text = """ #include typedef struct backlog_key { @@ -29,7 +32,7 @@ BPF_HISTOGRAM(dist, backlog_key_t); int do_entry(struct pt_regs *ctx) { struct sock *sk = (struct sock *)PT_REGS_PARM1(ctx); - + backlog_key_t key = {}; key.backlog = sk->sk_max_ack_backlog; key.slot = bpf_log2l(sk->sk_ack_backlog); @@ -37,9 +40,32 @@ int do_entry(struct pt_regs *ctx) { return 0; }; -""") -b.attach_kprobe(event="tcp_v4_syn_recv_sock", fn_name="do_entry") -b.attach_kprobe(event="tcp_v6_syn_recv_sock", fn_name="do_entry") +""" +examples = """examples: + ./tcpsynbl # trace syn backlog + ./tcpsynbl -4 # trace IPv4 family only + ./tcpsynbl -6 # trace IPv6 family only +""" +parser = argparse.ArgumentParser( + description="Show TCP SYN backlog.", + formatter_class=argparse.RawDescriptionHelpFormatter, + epilog=examples) +group = parser.add_mutually_exclusive_group() +group.add_argument("-4", "--ipv4", action="store_true", + help="trace IPv4 family only") +group.add_argument("-6", "--ipv6", action="store_true", + help="trace IPv6 family only") +args = parser.parse_args() + +b = BPF(text=bpf_text) + +if args.ipv4: + b.attach_kprobe(event="tcp_v4_syn_recv_sock", fn_name="do_entry") +elif args.ipv6: + b.attach_kprobe(event="tcp_v6_syn_recv_sock", fn_name="do_entry") +else: + b.attach_kprobe(event="tcp_v4_syn_recv_sock", fn_name="do_entry") + b.attach_kprobe(event="tcp_v6_syn_recv_sock", fn_name="do_entry") print("Tracing SYN backlog size. Ctrl-C to end."); diff --git a/tools/tcpsynbl_example.txt b/tools/tcpsynbl_example.txt index 1ac167df..716b55c1 100644 --- a/tools/tcpsynbl_example.txt +++ b/tools/tcpsynbl_example.txt @@ -18,3 +18,20 @@ backlog_max = 500L This output shows that for the backlog limit of 500, there were 961 SYN arrival where the backlog was zero or one, and one accept where the backlog was two or three. This indicates that we are nowhere near this limit. + +USAGE: + +# ./tcpsynbl -h +usage: tcpsynbl.py [-h] [-4 | -6] + +Show TCP SYN backlog. + +optional arguments: + -h, --help show this help message and exit + -4, --ipv4 trace IPv4 family only + -6, --ipv6 trace IPv6 family only + +examples: + ./tcpsynbl # trace syn backlog + ./tcpsynbl -4 # trace IPv4 family only + ./tcpsynbl -6 # trace IPv6 family only \ No newline at end of file diff --git a/tools/tcptop.py b/tools/tcptop.py index e9d0d1a2..76c91aff 100755 --- a/tools/tcptop.py +++ b/tools/tcptop.py @@ -4,7 +4,7 @@ # tcptop Summarize TCP send/recv throughput by host. # For Linux, uses BCC, eBPF. Embedded C. # -# USAGE: tcptop [-h] [-C] [-S] [-p PID] [interval [count]] +# USAGE: tcptop [-h] [-C] [-S] [-p PID] [interval [count]] [-4 | -6] # # This uses dynamic tracing of kernel functions, and will need to be updated # to match kernel changes. @@ -48,6 +48,8 @@ examples = """examples: ./tcptop -p 181 # only trace PID 181 ./tcptop --cgroupmap mappath # only trace cgroups in this BPF map ./tcptop --mntnsmap mappath # only trace mount namespaces in the map + ./tcptop -4 # trace IPv4 family only + ./tcptop -6 # trace IPv6 family only """ parser = argparse.ArgumentParser( description="Summarize TCP send/recv throughput by host", @@ -67,6 +69,11 @@ parser.add_argument("--cgroupmap", help="trace cgroups in this BPF map only") parser.add_argument("--mntnsmap", help="trace mount namespaces in this BPF map only") +group = parser.add_mutually_exclusive_group() +group.add_argument("-4", "--ipv4", action="store_true", + help="trace IPv4 family only") +group.add_argument("-6", "--ipv6", action="store_true", + help="trace IPv6 family only") parser.add_argument("--ebpf", action="store_true", help=argparse.SUPPRESS) args = parser.parse_args() @@ -114,6 +121,8 @@ int kprobe__tcp_sendmsg(struct pt_regs *ctx, struct sock *sk, u16 dport = 0, family = sk->__sk_common.skc_family; + FILTER_FAMILY + if (family == AF_INET) { struct ipv4_key_t ipv4_key = {.pid = pid}; ipv4_key.saddr = sk->__sk_common.skc_rcv_saddr; @@ -160,6 +169,8 @@ int kprobe__tcp_cleanup_rbuf(struct pt_regs *ctx, struct sock *sk, int copied) if (copied <= 0) return 0; + FILTER_FAMILY + if (family == AF_INET) { struct ipv4_key_t ipv4_key = {.pid = pid}; ipv4_key.saddr = sk->__sk_common.skc_rcv_saddr; @@ -192,6 +203,13 @@ if args.pid: 'if (pid != %s) { return 0; }' % args.pid) else: bpf_text = bpf_text.replace('FILTER_PID', '') +if args.ipv4: + bpf_text = bpf_text.replace('FILTER_FAMILY', + 'if (family != AF_INET) { return 0; }') +elif args.ipv6: + bpf_text = bpf_text.replace('FILTER_FAMILY', + 'if (family != AF_INET6) { return 0; }') +bpf_text = bpf_text.replace('FILTER_FAMILY', '') bpf_text = filter_by_containers(args) + bpf_text if debug or args.ebpf: print(bpf_text) diff --git a/tools/tcptop_example.txt b/tools/tcptop_example.txt index e29e2fa2..98064a9b 100644 --- a/tools/tcptop_example.txt +++ b/tools/tcptop_example.txt @@ -105,7 +105,7 @@ USAGE: # tcptop -h usage: tcptop.py [-h] [-C] [-S] [-p PID] [--cgroupmap CGROUPMAP] [--mntnsmap MNTNSMAP] - [interval] [count] + [interval] [count] [-4 | -6] Summarize TCP send/recv throughput by host @@ -120,6 +120,8 @@ optional arguments: -p PID, --pid PID trace this PID only --cgroupmap CGROUPMAP trace cgroups in this BPF map only + -4, --ipv4 trace IPv4 family only + -6, --ipv6 trace IPv6 family only examples: ./tcptop # trace TCP send/recv by host @@ -127,3 +129,5 @@ examples: ./tcptop -p 181 # only trace PID 181 ./tcptop --cgroupmap ./mappath # only trace cgroups in this BPF map ./tcptop --mntnsmap mappath # only trace mount namespaces in the map + ./tcptop -4 # trace IPv4 family only + ./tcptop -6 # trace IPv6 family only diff --git a/tools/tcptracer.py b/tools/tcptracer.py index 3220105e..25c6fd78 100755 --- a/tools/tcptracer.py +++ b/tools/tcptracer.py @@ -3,7 +3,7 @@ # tcpv4tracer Trace TCP connections. # For Linux, uses BCC, eBPF. Embedded C. # -# USAGE: tcpv4tracer [-h] [-v] [-p PID] [-N NETNS] +# USAGE: tcpv4tracer [-h] [-v] [-p PID] [-N NETNS] [-4 | -6] # # You should generally try to avoid writing long scripts that measure multiple # functions and walk multiple kernel structures, as they will be a burden to @@ -34,6 +34,11 @@ parser.add_argument("--cgroupmap", help="trace cgroups in this BPF map only") parser.add_argument("--mntnsmap", help="trace mount namespaces in this BPF map only") +group = parser.add_mutually_exclusive_group() +group.add_argument("-4", "--ipv4", action="store_true", + help="trace IPv4 family only") +group.add_argument("-6", "--ipv6", action="store_true", + help="trace IPv6 family only") parser.add_argument("-v", "--verbose", action="store_true", help="include Network Namespace in the output") parser.add_argument("--ebpf", action="store_true", @@ -185,6 +190,10 @@ int trace_connect_v4_entry(struct pt_regs *ctx, struct sock *sk) u64 pid = bpf_get_current_pid_tgid(); ##FILTER_PID## + + u16 family = sk->__sk_common.skc_family; + ##FILTER_FAMILY## + // stash the sock ptr for lookup on return connectsock.update(&pid, &sk); @@ -235,6 +244,8 @@ int trace_connect_v6_entry(struct pt_regs *ctx, struct sock *sk) u64 pid = bpf_get_current_pid_tgid(); ##FILTER_PID## + u16 family = sk->__sk_common.skc_family; + ##FILTER_FAMILY## // stash the sock ptr for lookup on return connectsock.update(&pid, &sk); @@ -283,6 +294,9 @@ int trace_tcp_set_state_entry(struct pt_regs *ctx, struct sock *skp, int state) return 0; } + u16 family = skp->__sk_common.skc_family; + ##FILTER_FAMILY## + u8 ipver = 0; if (check_family(skp, AF_INET)) { ipver = 4; @@ -371,6 +385,9 @@ int trace_close_entry(struct pt_regs *ctx, struct sock *skp) u64 pid = bpf_get_current_pid_tgid(); ##FILTER_PID## + + u16 family = skp->__sk_common.skc_family; + ##FILTER_FAMILY## u8 oldstate = skp->sk_state; // Don't generate close events for connections that were never @@ -456,6 +473,9 @@ int trace_accept_return(struct pt_regs *ctx) #endif ##FILTER_NETNS## + + u16 family = newsk->__sk_common.skc_family; + ##FILTER_FAMILY## if (check_family(newsk, AF_INET)) { ipver = 4; @@ -598,7 +618,13 @@ if args.pid: pid_filter = 'if (pid >> 32 != %d) { return 0; }' % args.pid if args.netns: netns_filter = 'if (net_ns_inum != %d) { return 0; }' % args.netns - +if args.ipv4: + bpf_text = bpf_text.replace('##FILTER_FAMILY##', + 'if (family != AF_INET) { return 0; }') +elif args.ipv6: + bpf_text = bpf_text.replace('##FILTER_FAMILY##', + 'if (family != AF_INET6) { return 0; }') +bpf_text = bpf_text.replace('##FILTER_FAMILY##', '') bpf_text = bpf_text.replace('##FILTER_PID##', pid_filter) bpf_text = bpf_text.replace('##FILTER_NETNS##', netns_filter) bpf_text = filter_by_containers(args) + bpf_text @@ -609,10 +635,17 @@ if args.ebpf: # initialize BPF b = BPF(text=bpf_text) -b.attach_kprobe(event="tcp_v4_connect", fn_name="trace_connect_v4_entry") -b.attach_kretprobe(event="tcp_v4_connect", fn_name="trace_connect_v4_return") -b.attach_kprobe(event="tcp_v6_connect", fn_name="trace_connect_v6_entry") -b.attach_kretprobe(event="tcp_v6_connect", fn_name="trace_connect_v6_return") +if args.ipv4: + b.attach_kprobe(event="tcp_v4_connect", fn_name="trace_connect_v4_entry") + b.attach_kretprobe(event="tcp_v4_connect", fn_name="trace_connect_v4_return") +elif args.ipv6: + b.attach_kprobe(event="tcp_v6_connect", fn_name="trace_connect_v6_entry") + b.attach_kretprobe(event="tcp_v6_connect", fn_name="trace_connect_v6_return") +else: + b.attach_kprobe(event="tcp_v4_connect", fn_name="trace_connect_v4_entry") + b.attach_kretprobe(event="tcp_v4_connect", fn_name="trace_connect_v4_return") + b.attach_kprobe(event="tcp_v6_connect", fn_name="trace_connect_v6_entry") + b.attach_kretprobe(event="tcp_v6_connect", fn_name="trace_connect_v6_return") b.attach_kprobe(event="tcp_set_state", fn_name="trace_tcp_set_state_entry") b.attach_kprobe(event="tcp_close", fn_name="trace_close_entry") b.attach_kretprobe(event="inet_csk_accept", fn_name="trace_accept_return") -- 2.34.1