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