xref: /aosp_15_r20/external/bcc/tools/tcpdrop.py (revision 387f9dfdfa2baef462e92476d413c7bc2470293e)
1*387f9dfdSAndroid Build Coastguard Worker#!/usr/bin/env python
2*387f9dfdSAndroid Build Coastguard Worker# @lint-avoid-python-3-compatibility-imports
3*387f9dfdSAndroid Build Coastguard Worker#
4*387f9dfdSAndroid Build Coastguard Worker# tcpdrop   Trace TCP kernel-dropped packets/segments.
5*387f9dfdSAndroid Build Coastguard Worker#           For Linux, uses BCC, eBPF. Embedded C.
6*387f9dfdSAndroid Build Coastguard Worker#
7*387f9dfdSAndroid Build Coastguard Worker# This provides information such as packet details, socket state, and kernel
8*387f9dfdSAndroid Build Coastguard Worker# stack trace for packets/segments that were dropped via tcp_drop().
9*387f9dfdSAndroid Build Coastguard Worker#
10*387f9dfdSAndroid Build Coastguard Worker# USAGE: tcpdrop [-4 | -6] [-h]
11*387f9dfdSAndroid Build Coastguard Worker#
12*387f9dfdSAndroid Build Coastguard Worker# This uses dynamic tracing of kernel functions, and will need to be updated
13*387f9dfdSAndroid Build Coastguard Worker# to match kernel changes.
14*387f9dfdSAndroid Build Coastguard Worker#
15*387f9dfdSAndroid Build Coastguard Worker# Copyright 2018 Netflix, Inc.
16*387f9dfdSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License")
17*387f9dfdSAndroid Build Coastguard Worker#
18*387f9dfdSAndroid Build Coastguard Worker# 30-May-2018   Brendan Gregg   Created this.
19*387f9dfdSAndroid Build Coastguard Worker# 15-Jun-2022   Rong Tao        Add tracepoint:skb:kfree_skb
20*387f9dfdSAndroid Build Coastguard Worker
21*387f9dfdSAndroid Build Coastguard Workerfrom __future__ import print_function
22*387f9dfdSAndroid Build Coastguard Workerfrom bcc import BPF
23*387f9dfdSAndroid Build Coastguard Workerimport argparse
24*387f9dfdSAndroid Build Coastguard Workerfrom time import strftime
25*387f9dfdSAndroid Build Coastguard Workerfrom socket import inet_ntop, AF_INET, AF_INET6
26*387f9dfdSAndroid Build Coastguard Workerfrom struct import pack
27*387f9dfdSAndroid Build Coastguard Workerfrom time import sleep
28*387f9dfdSAndroid Build Coastguard Workerfrom bcc import tcp
29*387f9dfdSAndroid Build Coastguard Worker
30*387f9dfdSAndroid Build Coastguard Worker# arguments
31*387f9dfdSAndroid Build Coastguard Workerexamples = """examples:
32*387f9dfdSAndroid Build Coastguard Worker    ./tcpdrop           # trace kernel TCP drops
33*387f9dfdSAndroid Build Coastguard Worker    ./tcpdrop -4        # trace IPv4 family only
34*387f9dfdSAndroid Build Coastguard Worker    ./tcpdrop -6        # trace IPv6 family only
35*387f9dfdSAndroid Build Coastguard Worker"""
36*387f9dfdSAndroid Build Coastguard Workerparser = argparse.ArgumentParser(
37*387f9dfdSAndroid Build Coastguard Worker    description="Trace TCP drops by the kernel",
38*387f9dfdSAndroid Build Coastguard Worker    formatter_class=argparse.RawDescriptionHelpFormatter,
39*387f9dfdSAndroid Build Coastguard Worker    epilog=examples)
40*387f9dfdSAndroid Build Coastguard Workergroup = parser.add_mutually_exclusive_group()
41*387f9dfdSAndroid Build Coastguard Workergroup.add_argument("-4", "--ipv4", action="store_true",
42*387f9dfdSAndroid Build Coastguard Worker    help="trace IPv4 family only")
43*387f9dfdSAndroid Build Coastguard Workergroup.add_argument("-6", "--ipv6", action="store_true",
44*387f9dfdSAndroid Build Coastguard Worker    help="trace IPv6 family only")
45*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("--ebpf", action="store_true",
46*387f9dfdSAndroid Build Coastguard Worker    help=argparse.SUPPRESS)
47*387f9dfdSAndroid Build Coastguard Workerargs = parser.parse_args()
48*387f9dfdSAndroid Build Coastguard Workerdebug = 0
49*387f9dfdSAndroid Build Coastguard Worker
50*387f9dfdSAndroid Build Coastguard Worker# define BPF program
51*387f9dfdSAndroid Build Coastguard Workerbpf_text = """
52*387f9dfdSAndroid Build Coastguard Worker#include <uapi/linux/ptrace.h>
53*387f9dfdSAndroid Build Coastguard Worker#include <uapi/linux/tcp.h>
54*387f9dfdSAndroid Build Coastguard Worker#include <uapi/linux/ip.h>
55*387f9dfdSAndroid Build Coastguard Worker#include <net/sock.h>
56*387f9dfdSAndroid Build Coastguard Worker#include <bcc/proto.h>
57*387f9dfdSAndroid Build Coastguard Worker
58*387f9dfdSAndroid Build Coastguard WorkerBPF_STACK_TRACE(stack_traces, 1024);
59*387f9dfdSAndroid Build Coastguard Worker
60*387f9dfdSAndroid Build Coastguard Worker// separate data structs for ipv4 and ipv6
61*387f9dfdSAndroid Build Coastguard Workerstruct ipv4_data_t {
62*387f9dfdSAndroid Build Coastguard Worker    u32 pid;
63*387f9dfdSAndroid Build Coastguard Worker    u64 ip;
64*387f9dfdSAndroid Build Coastguard Worker    u32 saddr;
65*387f9dfdSAndroid Build Coastguard Worker    u32 daddr;
66*387f9dfdSAndroid Build Coastguard Worker    u16 sport;
67*387f9dfdSAndroid Build Coastguard Worker    u16 dport;
68*387f9dfdSAndroid Build Coastguard Worker    u8 state;
69*387f9dfdSAndroid Build Coastguard Worker    u8 tcpflags;
70*387f9dfdSAndroid Build Coastguard Worker    u32 stack_id;
71*387f9dfdSAndroid Build Coastguard Worker};
72*387f9dfdSAndroid Build Coastguard WorkerBPF_PERF_OUTPUT(ipv4_events);
73*387f9dfdSAndroid Build Coastguard Worker
74*387f9dfdSAndroid Build Coastguard Workerstruct ipv6_data_t {
75*387f9dfdSAndroid Build Coastguard Worker    u32 pid;
76*387f9dfdSAndroid Build Coastguard Worker    u64 ip;
77*387f9dfdSAndroid Build Coastguard Worker    unsigned __int128 saddr;
78*387f9dfdSAndroid Build Coastguard Worker    unsigned __int128 daddr;
79*387f9dfdSAndroid Build Coastguard Worker    u16 sport;
80*387f9dfdSAndroid Build Coastguard Worker    u16 dport;
81*387f9dfdSAndroid Build Coastguard Worker    u8 state;
82*387f9dfdSAndroid Build Coastguard Worker    u8 tcpflags;
83*387f9dfdSAndroid Build Coastguard Worker    u32 stack_id;
84*387f9dfdSAndroid Build Coastguard Worker};
85*387f9dfdSAndroid Build Coastguard WorkerBPF_PERF_OUTPUT(ipv6_events);
86*387f9dfdSAndroid Build Coastguard Worker
87*387f9dfdSAndroid Build Coastguard Workerstatic struct tcphdr *skb_to_tcphdr(const struct sk_buff *skb)
88*387f9dfdSAndroid Build Coastguard Worker{
89*387f9dfdSAndroid Build Coastguard Worker    // unstable API. verify logic in tcp_hdr() -> skb_transport_header().
90*387f9dfdSAndroid Build Coastguard Worker    return (struct tcphdr *)(skb->head + skb->transport_header);
91*387f9dfdSAndroid Build Coastguard Worker}
92*387f9dfdSAndroid Build Coastguard Worker
93*387f9dfdSAndroid Build Coastguard Workerstatic inline struct iphdr *skb_to_iphdr(const struct sk_buff *skb)
94*387f9dfdSAndroid Build Coastguard Worker{
95*387f9dfdSAndroid Build Coastguard Worker    // unstable API. verify logic in ip_hdr() -> skb_network_header().
96*387f9dfdSAndroid Build Coastguard Worker    return (struct iphdr *)(skb->head + skb->network_header);
97*387f9dfdSAndroid Build Coastguard Worker}
98*387f9dfdSAndroid Build Coastguard Worker
99*387f9dfdSAndroid Build Coastguard Worker// from include/net/tcp.h:
100*387f9dfdSAndroid Build Coastguard Worker#ifndef tcp_flag_byte
101*387f9dfdSAndroid Build Coastguard Worker#define tcp_flag_byte(th) (((u_int8_t *)th)[13])
102*387f9dfdSAndroid Build Coastguard Worker#endif
103*387f9dfdSAndroid Build Coastguard Worker
104*387f9dfdSAndroid Build Coastguard Workerstatic int __trace_tcp_drop(void *ctx, struct sock *sk, struct sk_buff *skb)
105*387f9dfdSAndroid Build Coastguard Worker{
106*387f9dfdSAndroid Build Coastguard Worker    if (sk == NULL)
107*387f9dfdSAndroid Build Coastguard Worker        return 0;
108*387f9dfdSAndroid Build Coastguard Worker    u32 pid = bpf_get_current_pid_tgid() >> 32;
109*387f9dfdSAndroid Build Coastguard Worker
110*387f9dfdSAndroid Build Coastguard Worker    // pull in details from the packet headers and the sock struct
111*387f9dfdSAndroid Build Coastguard Worker    u16 family = sk->__sk_common.skc_family;
112*387f9dfdSAndroid Build Coastguard Worker    char state = sk->__sk_common.skc_state;
113*387f9dfdSAndroid Build Coastguard Worker    u16 sport = 0, dport = 0;
114*387f9dfdSAndroid Build Coastguard Worker    struct tcphdr *tcp = skb_to_tcphdr(skb);
115*387f9dfdSAndroid Build Coastguard Worker    struct iphdr *ip = skb_to_iphdr(skb);
116*387f9dfdSAndroid Build Coastguard Worker    u8 tcpflags = ((u_int8_t *)tcp)[13];
117*387f9dfdSAndroid Build Coastguard Worker    sport = tcp->source;
118*387f9dfdSAndroid Build Coastguard Worker    dport = tcp->dest;
119*387f9dfdSAndroid Build Coastguard Worker    sport = ntohs(sport);
120*387f9dfdSAndroid Build Coastguard Worker    dport = ntohs(dport);
121*387f9dfdSAndroid Build Coastguard Worker
122*387f9dfdSAndroid Build Coastguard Worker    FILTER_FAMILY
123*387f9dfdSAndroid Build Coastguard Worker
124*387f9dfdSAndroid Build Coastguard Worker    if (family == AF_INET) {
125*387f9dfdSAndroid Build Coastguard Worker        struct ipv4_data_t data4 = {};
126*387f9dfdSAndroid Build Coastguard Worker        data4.pid = pid;
127*387f9dfdSAndroid Build Coastguard Worker        data4.ip = 4;
128*387f9dfdSAndroid Build Coastguard Worker        data4.saddr = ip->saddr;
129*387f9dfdSAndroid Build Coastguard Worker        data4.daddr = ip->daddr;
130*387f9dfdSAndroid Build Coastguard Worker        data4.dport = dport;
131*387f9dfdSAndroid Build Coastguard Worker        data4.sport = sport;
132*387f9dfdSAndroid Build Coastguard Worker        data4.state = state;
133*387f9dfdSAndroid Build Coastguard Worker        data4.tcpflags = tcpflags;
134*387f9dfdSAndroid Build Coastguard Worker        data4.stack_id = stack_traces.get_stackid(ctx, 0);
135*387f9dfdSAndroid Build Coastguard Worker        ipv4_events.perf_submit(ctx, &data4, sizeof(data4));
136*387f9dfdSAndroid Build Coastguard Worker
137*387f9dfdSAndroid Build Coastguard Worker    } else if (family == AF_INET6) {
138*387f9dfdSAndroid Build Coastguard Worker        struct ipv6_data_t data6 = {};
139*387f9dfdSAndroid Build Coastguard Worker        data6.pid = pid;
140*387f9dfdSAndroid Build Coastguard Worker        data6.ip = 6;
141*387f9dfdSAndroid Build Coastguard Worker        // The remote address (skc_v6_daddr) was the source
142*387f9dfdSAndroid Build Coastguard Worker        bpf_probe_read_kernel(&data6.saddr, sizeof(data6.saddr),
143*387f9dfdSAndroid Build Coastguard Worker            sk->__sk_common.skc_v6_daddr.in6_u.u6_addr32);
144*387f9dfdSAndroid Build Coastguard Worker        // The local address (skc_v6_rcv_saddr) was the destination
145*387f9dfdSAndroid Build Coastguard Worker        bpf_probe_read_kernel(&data6.daddr, sizeof(data6.daddr),
146*387f9dfdSAndroid Build Coastguard Worker            sk->__sk_common.skc_v6_rcv_saddr.in6_u.u6_addr32);
147*387f9dfdSAndroid Build Coastguard Worker        data6.dport = dport;
148*387f9dfdSAndroid Build Coastguard Worker        data6.sport = sport;
149*387f9dfdSAndroid Build Coastguard Worker        data6.state = state;
150*387f9dfdSAndroid Build Coastguard Worker        data6.tcpflags = tcpflags;
151*387f9dfdSAndroid Build Coastguard Worker        data6.stack_id = stack_traces.get_stackid(ctx, 0);
152*387f9dfdSAndroid Build Coastguard Worker        ipv6_events.perf_submit(ctx, &data6, sizeof(data6));
153*387f9dfdSAndroid Build Coastguard Worker    }
154*387f9dfdSAndroid Build Coastguard Worker    // else drop
155*387f9dfdSAndroid Build Coastguard Worker
156*387f9dfdSAndroid Build Coastguard Worker    return 0;
157*387f9dfdSAndroid Build Coastguard Worker}
158*387f9dfdSAndroid Build Coastguard Worker
159*387f9dfdSAndroid Build Coastguard Workerint trace_tcp_drop(struct pt_regs *ctx, struct sock *sk, struct sk_buff *skb)
160*387f9dfdSAndroid Build Coastguard Worker{
161*387f9dfdSAndroid Build Coastguard Worker    return __trace_tcp_drop(ctx, sk, skb);
162*387f9dfdSAndroid Build Coastguard Worker}
163*387f9dfdSAndroid Build Coastguard Worker"""
164*387f9dfdSAndroid Build Coastguard Worker
165*387f9dfdSAndroid Build Coastguard Workerbpf_kfree_skb_text = """
166*387f9dfdSAndroid Build Coastguard Worker#include <linux/skbuff.h>
167*387f9dfdSAndroid Build Coastguard Worker
168*387f9dfdSAndroid Build Coastguard WorkerTRACEPOINT_PROBE(skb, kfree_skb) {
169*387f9dfdSAndroid Build Coastguard Worker    struct sk_buff *skb = args->skbaddr;
170*387f9dfdSAndroid Build Coastguard Worker    struct sock *sk = skb->sk;
171*387f9dfdSAndroid Build Coastguard Worker    enum skb_drop_reason reason = args->reason;
172*387f9dfdSAndroid Build Coastguard Worker
173*387f9dfdSAndroid Build Coastguard Worker    // SKB_NOT_DROPPED_YET,
174*387f9dfdSAndroid Build Coastguard Worker    // SKB_DROP_REASON_NOT_SPECIFIED,
175*387f9dfdSAndroid Build Coastguard Worker    if (reason > SKB_DROP_REASON_NOT_SPECIFIED) {
176*387f9dfdSAndroid Build Coastguard Worker        return __trace_tcp_drop(args, sk, skb);
177*387f9dfdSAndroid Build Coastguard Worker    }
178*387f9dfdSAndroid Build Coastguard Worker
179*387f9dfdSAndroid Build Coastguard Worker    return 0;
180*387f9dfdSAndroid Build Coastguard Worker}
181*387f9dfdSAndroid Build Coastguard Worker"""
182*387f9dfdSAndroid Build Coastguard Worker
183*387f9dfdSAndroid Build Coastguard Workerif debug or args.ebpf:
184*387f9dfdSAndroid Build Coastguard Worker    print(bpf_text)
185*387f9dfdSAndroid Build Coastguard Worker    if args.ebpf:
186*387f9dfdSAndroid Build Coastguard Worker        exit()
187*387f9dfdSAndroid Build Coastguard Workerif args.ipv4:
188*387f9dfdSAndroid Build Coastguard Worker    bpf_text = bpf_text.replace('FILTER_FAMILY',
189*387f9dfdSAndroid Build Coastguard Worker        'if (family != AF_INET) { return 0; }')
190*387f9dfdSAndroid Build Coastguard Workerelif args.ipv6:
191*387f9dfdSAndroid Build Coastguard Worker    bpf_text = bpf_text.replace('FILTER_FAMILY',
192*387f9dfdSAndroid Build Coastguard Worker        'if (family != AF_INET6) { return 0; }')
193*387f9dfdSAndroid Build Coastguard Workerelse:
194*387f9dfdSAndroid Build Coastguard Worker    bpf_text = bpf_text.replace('FILTER_FAMILY', '')
195*387f9dfdSAndroid Build Coastguard Worker
196*387f9dfdSAndroid Build Coastguard Worker# process event
197*387f9dfdSAndroid Build Coastguard Workerdef print_ipv4_event(cpu, data, size):
198*387f9dfdSAndroid Build Coastguard Worker    event = b["ipv4_events"].event(data)
199*387f9dfdSAndroid Build Coastguard Worker    print("%-8s %-7d %-2d %-20s > %-20s %s (%s)" % (
200*387f9dfdSAndroid Build Coastguard Worker        strftime("%H:%M:%S"), event.pid, event.ip,
201*387f9dfdSAndroid Build Coastguard Worker        "%s:%d" % (inet_ntop(AF_INET, pack('I', event.saddr)), event.sport),
202*387f9dfdSAndroid Build Coastguard Worker        "%s:%s" % (inet_ntop(AF_INET, pack('I', event.daddr)), event.dport),
203*387f9dfdSAndroid Build Coastguard Worker        tcp.tcpstate[event.state], tcp.flags2str(event.tcpflags)))
204*387f9dfdSAndroid Build Coastguard Worker    for addr in stack_traces.walk(event.stack_id):
205*387f9dfdSAndroid Build Coastguard Worker        sym = b.ksym(addr, show_offset=True)
206*387f9dfdSAndroid Build Coastguard Worker        print("\t%s" % sym)
207*387f9dfdSAndroid Build Coastguard Worker    print("")
208*387f9dfdSAndroid Build Coastguard Worker
209*387f9dfdSAndroid Build Coastguard Workerdef print_ipv6_event(cpu, data, size):
210*387f9dfdSAndroid Build Coastguard Worker    event = b["ipv6_events"].event(data)
211*387f9dfdSAndroid Build Coastguard Worker    print("%-8s %-7d %-2d %-20s > %-20s %s (%s)" % (
212*387f9dfdSAndroid Build Coastguard Worker        strftime("%H:%M:%S"), event.pid, event.ip,
213*387f9dfdSAndroid Build Coastguard Worker        "%s:%d" % (inet_ntop(AF_INET6, event.saddr), event.sport),
214*387f9dfdSAndroid Build Coastguard Worker        "%s:%d" % (inet_ntop(AF_INET6, event.daddr), event.dport),
215*387f9dfdSAndroid Build Coastguard Worker        tcp.tcpstate[event.state], tcp.flags2str(event.tcpflags)))
216*387f9dfdSAndroid Build Coastguard Worker    for addr in stack_traces.walk(event.stack_id):
217*387f9dfdSAndroid Build Coastguard Worker        sym = b.ksym(addr, show_offset=True)
218*387f9dfdSAndroid Build Coastguard Worker        print("\t%s" % sym)
219*387f9dfdSAndroid Build Coastguard Worker    print("")
220*387f9dfdSAndroid Build Coastguard Worker
221*387f9dfdSAndroid Build Coastguard Workerif BPF.tracepoint_exists("skb", "kfree_skb"):
222*387f9dfdSAndroid Build Coastguard Worker    if BPF.kernel_struct_has_field("trace_event_raw_kfree_skb", "reason") == 1:
223*387f9dfdSAndroid Build Coastguard Worker        bpf_text += bpf_kfree_skb_text
224*387f9dfdSAndroid Build Coastguard Worker
225*387f9dfdSAndroid Build Coastguard Worker# initialize BPF
226*387f9dfdSAndroid Build Coastguard Workerb = BPF(text=bpf_text)
227*387f9dfdSAndroid Build Coastguard Worker
228*387f9dfdSAndroid Build Coastguard Workerif b.get_kprobe_functions(b"tcp_drop"):
229*387f9dfdSAndroid Build Coastguard Worker    b.attach_kprobe(event="tcp_drop", fn_name="trace_tcp_drop")
230*387f9dfdSAndroid Build Coastguard Workerelif b.tracepoint_exists("skb", "kfree_skb"):
231*387f9dfdSAndroid Build Coastguard Worker    print("WARNING: tcp_drop() kernel function not found or traceable. "
232*387f9dfdSAndroid Build Coastguard Worker          "Use tracpoint:skb:kfree_skb instead.")
233*387f9dfdSAndroid Build Coastguard Workerelse:
234*387f9dfdSAndroid Build Coastguard Worker    print("ERROR: tcp_drop() kernel function and tracpoint:skb:kfree_skb"
235*387f9dfdSAndroid Build Coastguard Worker          " not found or traceable. "
236*387f9dfdSAndroid Build Coastguard Worker          "The kernel might be too old or the the function has been inlined.")
237*387f9dfdSAndroid Build Coastguard Worker    exit()
238*387f9dfdSAndroid Build Coastguard Workerstack_traces = b.get_table("stack_traces")
239*387f9dfdSAndroid Build Coastguard Worker
240*387f9dfdSAndroid Build Coastguard Worker# header
241*387f9dfdSAndroid Build Coastguard Workerprint("%-8s %-7s %-2s %-20s > %-20s %s (%s)" % ("TIME", "PID", "IP",
242*387f9dfdSAndroid Build Coastguard Worker    "SADDR:SPORT", "DADDR:DPORT", "STATE", "FLAGS"))
243*387f9dfdSAndroid Build Coastguard Worker
244*387f9dfdSAndroid Build Coastguard Worker# read events
245*387f9dfdSAndroid Build Coastguard Workerb["ipv4_events"].open_perf_buffer(print_ipv4_event)
246*387f9dfdSAndroid Build Coastguard Workerb["ipv6_events"].open_perf_buffer(print_ipv6_event)
247*387f9dfdSAndroid Build Coastguard Workerwhile 1:
248*387f9dfdSAndroid Build Coastguard Worker    try:
249*387f9dfdSAndroid Build Coastguard Worker        b.perf_buffer_poll()
250*387f9dfdSAndroid Build Coastguard Worker    except KeyboardInterrupt:
251*387f9dfdSAndroid Build Coastguard Worker        exit()
252