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# tcplife Trace the lifespan of TCP sessions and summarize. 5*387f9dfdSAndroid Build Coastguard Worker# For Linux, uses BCC, BPF. Embedded C. 6*387f9dfdSAndroid Build Coastguard Worker# 7*387f9dfdSAndroid Build Coastguard Worker# USAGE: tcplife [-h] [-C] [-S] [-p PID] [-4 | -6] [interval [count]] 8*387f9dfdSAndroid Build Coastguard Worker# 9*387f9dfdSAndroid Build Coastguard Worker# This uses the sock:inet_sock_set_state tracepoint if it exists (added to 10*387f9dfdSAndroid Build Coastguard Worker# Linux 4.16, and replacing the earlier tcp:tcp_set_state), else it uses 11*387f9dfdSAndroid Build Coastguard Worker# kernel dynamic tracing of tcp_set_state(). 12*387f9dfdSAndroid Build Coastguard Worker# 13*387f9dfdSAndroid Build Coastguard Worker# While throughput counters are emitted, they are fetched in a low-overhead 14*387f9dfdSAndroid Build Coastguard Worker# manner: reading members of the tcp_info struct on TCP close. ie, we do not 15*387f9dfdSAndroid Build Coastguard Worker# trace send/receive. 16*387f9dfdSAndroid Build Coastguard Worker# 17*387f9dfdSAndroid Build Coastguard Worker# Copyright 2016 Netflix, Inc. 18*387f9dfdSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License") 19*387f9dfdSAndroid Build Coastguard Worker# 20*387f9dfdSAndroid Build Coastguard Worker# IDEA: Julia Evans 21*387f9dfdSAndroid Build Coastguard Worker# 22*387f9dfdSAndroid Build Coastguard Worker# 18-Oct-2016 Brendan Gregg Created this. 23*387f9dfdSAndroid Build Coastguard Worker# 29-Dec-2017 " " Added tracepoint support. 24*387f9dfdSAndroid Build Coastguard Worker 25*387f9dfdSAndroid Build Coastguard Workerfrom __future__ import print_function 26*387f9dfdSAndroid Build Coastguard Workerfrom bcc import BPF 27*387f9dfdSAndroid Build Coastguard Workerimport argparse 28*387f9dfdSAndroid Build Coastguard Workerfrom socket import inet_ntop, AF_INET, AF_INET6 29*387f9dfdSAndroid Build Coastguard Workerfrom struct import pack 30*387f9dfdSAndroid Build Coastguard Workerfrom time import strftime 31*387f9dfdSAndroid Build Coastguard Worker 32*387f9dfdSAndroid Build Coastguard Worker# arguments 33*387f9dfdSAndroid Build Coastguard Workerexamples = """examples: 34*387f9dfdSAndroid Build Coastguard Worker ./tcplife # trace all TCP connect()s 35*387f9dfdSAndroid Build Coastguard Worker ./tcplife -T # include time column (HH:MM:SS) 36*387f9dfdSAndroid Build Coastguard Worker ./tcplife -w # wider columns (fit IPv6) 37*387f9dfdSAndroid Build Coastguard Worker ./tcplife -stT # csv output, with times & timestamps 38*387f9dfdSAndroid Build Coastguard Worker ./tcplife -p 181 # only trace PID 181 39*387f9dfdSAndroid Build Coastguard Worker ./tcplife -L 80 # only trace local port 80 40*387f9dfdSAndroid Build Coastguard Worker ./tcplife -L 80,81 # only trace local ports 80 and 81 41*387f9dfdSAndroid Build Coastguard Worker ./tcplife -D 80 # only trace remote port 80 42*387f9dfdSAndroid Build Coastguard Worker ./tcplife -4 # only trace IPv4 family 43*387f9dfdSAndroid Build Coastguard Worker ./tcplife -6 # only trace IPv6 family 44*387f9dfdSAndroid Build Coastguard Worker""" 45*387f9dfdSAndroid Build Coastguard Workerparser = argparse.ArgumentParser( 46*387f9dfdSAndroid Build Coastguard Worker description="Trace the lifespan of TCP sessions and summarize", 47*387f9dfdSAndroid Build Coastguard Worker formatter_class=argparse.RawDescriptionHelpFormatter, 48*387f9dfdSAndroid Build Coastguard Worker epilog=examples) 49*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-T", "--time", action="store_true", 50*387f9dfdSAndroid Build Coastguard Worker help="include time column on output (HH:MM:SS)") 51*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-t", "--timestamp", action="store_true", 52*387f9dfdSAndroid Build Coastguard Worker help="include timestamp on output (seconds)") 53*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-w", "--wide", action="store_true", 54*387f9dfdSAndroid Build Coastguard Worker help="wide column output (fits IPv6 addresses)") 55*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-s", "--csv", action="store_true", 56*387f9dfdSAndroid Build Coastguard Worker help="comma separated values output") 57*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-p", "--pid", 58*387f9dfdSAndroid Build Coastguard Worker help="trace this PID only") 59*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-L", "--localport", 60*387f9dfdSAndroid Build Coastguard Worker help="comma-separated list of local ports to trace.") 61*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-D", "--remoteport", 62*387f9dfdSAndroid Build Coastguard Worker help="comma-separated list of remote ports to trace.") 63*387f9dfdSAndroid Build Coastguard Workergroup = parser.add_mutually_exclusive_group() 64*387f9dfdSAndroid Build Coastguard Workergroup.add_argument("-4", "--ipv4", action="store_true", 65*387f9dfdSAndroid Build Coastguard Worker help="trace IPv4 family only") 66*387f9dfdSAndroid Build Coastguard Workergroup.add_argument("-6", "--ipv6", action="store_true", 67*387f9dfdSAndroid Build Coastguard Worker help="trace IPv6 family only") 68*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("--ebpf", action="store_true", 69*387f9dfdSAndroid Build Coastguard Worker help=argparse.SUPPRESS) 70*387f9dfdSAndroid Build Coastguard Workerargs = parser.parse_args() 71*387f9dfdSAndroid Build Coastguard Workerdebug = 0 72*387f9dfdSAndroid Build Coastguard Worker 73*387f9dfdSAndroid Build Coastguard Worker# define BPF program 74*387f9dfdSAndroid Build Coastguard Workerbpf_text = """ 75*387f9dfdSAndroid Build Coastguard Worker#include <uapi/linux/ptrace.h> 76*387f9dfdSAndroid Build Coastguard Worker#include <linux/tcp.h> 77*387f9dfdSAndroid Build Coastguard Worker#include <net/sock.h> 78*387f9dfdSAndroid Build Coastguard Worker#include <bcc/proto.h> 79*387f9dfdSAndroid Build Coastguard Worker 80*387f9dfdSAndroid Build Coastguard WorkerBPF_HASH(birth, struct sock *, u64); 81*387f9dfdSAndroid Build Coastguard Worker 82*387f9dfdSAndroid Build Coastguard Worker// separate data structs for ipv4 and ipv6 83*387f9dfdSAndroid Build Coastguard Workerstruct ipv4_data_t { 84*387f9dfdSAndroid Build Coastguard Worker u64 ts_us; 85*387f9dfdSAndroid Build Coastguard Worker u32 pid; 86*387f9dfdSAndroid Build Coastguard Worker u32 saddr; 87*387f9dfdSAndroid Build Coastguard Worker u32 daddr; 88*387f9dfdSAndroid Build Coastguard Worker u64 ports; 89*387f9dfdSAndroid Build Coastguard Worker u64 rx_b; 90*387f9dfdSAndroid Build Coastguard Worker u64 tx_b; 91*387f9dfdSAndroid Build Coastguard Worker u64 span_us; 92*387f9dfdSAndroid Build Coastguard Worker char task[TASK_COMM_LEN]; 93*387f9dfdSAndroid Build Coastguard Worker}; 94*387f9dfdSAndroid Build Coastguard WorkerBPF_PERF_OUTPUT(ipv4_events); 95*387f9dfdSAndroid Build Coastguard Worker 96*387f9dfdSAndroid Build Coastguard Workerstruct ipv6_data_t { 97*387f9dfdSAndroid Build Coastguard Worker u64 ts_us; 98*387f9dfdSAndroid Build Coastguard Worker u32 pid; 99*387f9dfdSAndroid Build Coastguard Worker unsigned __int128 saddr; 100*387f9dfdSAndroid Build Coastguard Worker unsigned __int128 daddr; 101*387f9dfdSAndroid Build Coastguard Worker u64 ports; 102*387f9dfdSAndroid Build Coastguard Worker u64 rx_b; 103*387f9dfdSAndroid Build Coastguard Worker u64 tx_b; 104*387f9dfdSAndroid Build Coastguard Worker u64 span_us; 105*387f9dfdSAndroid Build Coastguard Worker char task[TASK_COMM_LEN]; 106*387f9dfdSAndroid Build Coastguard Worker}; 107*387f9dfdSAndroid Build Coastguard WorkerBPF_PERF_OUTPUT(ipv6_events); 108*387f9dfdSAndroid Build Coastguard Worker 109*387f9dfdSAndroid Build Coastguard Workerstruct id_t { 110*387f9dfdSAndroid Build Coastguard Worker u32 pid; 111*387f9dfdSAndroid Build Coastguard Worker char task[TASK_COMM_LEN]; 112*387f9dfdSAndroid Build Coastguard Worker}; 113*387f9dfdSAndroid Build Coastguard WorkerBPF_HASH(whoami, struct sock *, struct id_t); 114*387f9dfdSAndroid Build Coastguard Worker""" 115*387f9dfdSAndroid Build Coastguard Worker 116*387f9dfdSAndroid Build Coastguard Worker# 117*387f9dfdSAndroid Build Coastguard Worker# XXX: The following is temporary code for older kernels, Linux 4.14 and 118*387f9dfdSAndroid Build Coastguard Worker# older. It uses kprobes to instrument tcp_set_state(). On Linux 4.16 and 119*387f9dfdSAndroid Build Coastguard Worker# later, the sock:inet_sock_set_state tracepoint should be used instead, as 120*387f9dfdSAndroid Build Coastguard Worker# is done by the code that follows this. In the distant future (2021?), this 121*387f9dfdSAndroid Build Coastguard Worker# kprobe code can be removed. This is why there is so much code 122*387f9dfdSAndroid Build Coastguard Worker# duplication: to make removal easier. 123*387f9dfdSAndroid Build Coastguard Worker# 124*387f9dfdSAndroid Build Coastguard Workerbpf_text_kprobe = """ 125*387f9dfdSAndroid Build Coastguard Workerint kprobe__tcp_set_state(struct pt_regs *ctx, struct sock *sk, int state) 126*387f9dfdSAndroid Build Coastguard Worker{ 127*387f9dfdSAndroid Build Coastguard Worker u32 pid = bpf_get_current_pid_tgid() >> 32; 128*387f9dfdSAndroid Build Coastguard Worker 129*387f9dfdSAndroid Build Coastguard Worker // lport is either used in a filter here, or later 130*387f9dfdSAndroid Build Coastguard Worker u16 lport = sk->__sk_common.skc_num; 131*387f9dfdSAndroid Build Coastguard Worker FILTER_LPORT 132*387f9dfdSAndroid Build Coastguard Worker 133*387f9dfdSAndroid Build Coastguard Worker // dport is either used in a filter here, or later 134*387f9dfdSAndroid Build Coastguard Worker u16 dport = sk->__sk_common.skc_dport; 135*387f9dfdSAndroid Build Coastguard Worker dport = ntohs(dport); 136*387f9dfdSAndroid Build Coastguard Worker FILTER_DPORT 137*387f9dfdSAndroid Build Coastguard Worker 138*387f9dfdSAndroid Build Coastguard Worker /* 139*387f9dfdSAndroid Build Coastguard Worker * This tool includes PID and comm context. It's best effort, and may 140*387f9dfdSAndroid Build Coastguard Worker * be wrong in some situations. It currently works like this: 141*387f9dfdSAndroid Build Coastguard Worker * - record timestamp on any state < TCP_FIN_WAIT1 142*387f9dfdSAndroid Build Coastguard Worker * - cache task context on: 143*387f9dfdSAndroid Build Coastguard Worker * TCP_SYN_SENT: tracing from client 144*387f9dfdSAndroid Build Coastguard Worker * TCP_LAST_ACK: client-closed from server 145*387f9dfdSAndroid Build Coastguard Worker * - do output on TCP_CLOSE: 146*387f9dfdSAndroid Build Coastguard Worker * fetch task context if cached, or use current task 147*387f9dfdSAndroid Build Coastguard Worker */ 148*387f9dfdSAndroid Build Coastguard Worker 149*387f9dfdSAndroid Build Coastguard Worker // capture birth time 150*387f9dfdSAndroid Build Coastguard Worker if (state < TCP_FIN_WAIT1) { 151*387f9dfdSAndroid Build Coastguard Worker /* 152*387f9dfdSAndroid Build Coastguard Worker * Matching just ESTABLISHED may be sufficient, provided no code-path 153*387f9dfdSAndroid Build Coastguard Worker * sets ESTABLISHED without a tcp_set_state() call. Until we know 154*387f9dfdSAndroid Build Coastguard Worker * that for sure, match all early states to increase chances a 155*387f9dfdSAndroid Build Coastguard Worker * timestamp is set. 156*387f9dfdSAndroid Build Coastguard Worker * Note that this needs to be set before the PID filter later on, 157*387f9dfdSAndroid Build Coastguard Worker * since the PID isn't reliable for these early stages, so we must 158*387f9dfdSAndroid Build Coastguard Worker * save all timestamps and do the PID filter later when we can. 159*387f9dfdSAndroid Build Coastguard Worker */ 160*387f9dfdSAndroid Build Coastguard Worker u64 ts = bpf_ktime_get_ns(); 161*387f9dfdSAndroid Build Coastguard Worker birth.update(&sk, &ts); 162*387f9dfdSAndroid Build Coastguard Worker } 163*387f9dfdSAndroid Build Coastguard Worker 164*387f9dfdSAndroid Build Coastguard Worker // record PID & comm on SYN_SENT 165*387f9dfdSAndroid Build Coastguard Worker if (state == TCP_SYN_SENT || state == TCP_LAST_ACK) { 166*387f9dfdSAndroid Build Coastguard Worker // now we can PID filter, both here and a little later on for CLOSE 167*387f9dfdSAndroid Build Coastguard Worker FILTER_PID 168*387f9dfdSAndroid Build Coastguard Worker struct id_t me = {.pid = pid}; 169*387f9dfdSAndroid Build Coastguard Worker bpf_get_current_comm(&me.task, sizeof(me.task)); 170*387f9dfdSAndroid Build Coastguard Worker whoami.update(&sk, &me); 171*387f9dfdSAndroid Build Coastguard Worker } 172*387f9dfdSAndroid Build Coastguard Worker 173*387f9dfdSAndroid Build Coastguard Worker if (state != TCP_CLOSE) 174*387f9dfdSAndroid Build Coastguard Worker return 0; 175*387f9dfdSAndroid Build Coastguard Worker 176*387f9dfdSAndroid Build Coastguard Worker // calculate lifespan 177*387f9dfdSAndroid Build Coastguard Worker u64 *tsp, delta_us; 178*387f9dfdSAndroid Build Coastguard Worker tsp = birth.lookup(&sk); 179*387f9dfdSAndroid Build Coastguard Worker if (tsp == 0) { 180*387f9dfdSAndroid Build Coastguard Worker whoami.delete(&sk); // may not exist 181*387f9dfdSAndroid Build Coastguard Worker return 0; // missed create 182*387f9dfdSAndroid Build Coastguard Worker } 183*387f9dfdSAndroid Build Coastguard Worker delta_us = (bpf_ktime_get_ns() - *tsp) / 1000; 184*387f9dfdSAndroid Build Coastguard Worker birth.delete(&sk); 185*387f9dfdSAndroid Build Coastguard Worker 186*387f9dfdSAndroid Build Coastguard Worker // fetch possible cached data, and filter 187*387f9dfdSAndroid Build Coastguard Worker struct id_t *mep; 188*387f9dfdSAndroid Build Coastguard Worker mep = whoami.lookup(&sk); 189*387f9dfdSAndroid Build Coastguard Worker if (mep != 0) 190*387f9dfdSAndroid Build Coastguard Worker pid = mep->pid; 191*387f9dfdSAndroid Build Coastguard Worker FILTER_PID 192*387f9dfdSAndroid Build Coastguard Worker 193*387f9dfdSAndroid Build Coastguard Worker // get throughput stats. see tcp_get_info(). 194*387f9dfdSAndroid Build Coastguard Worker u64 rx_b = 0, tx_b = 0; 195*387f9dfdSAndroid Build Coastguard Worker struct tcp_sock *tp = (struct tcp_sock *)sk; 196*387f9dfdSAndroid Build Coastguard Worker rx_b = tp->bytes_received; 197*387f9dfdSAndroid Build Coastguard Worker tx_b = tp->bytes_acked; 198*387f9dfdSAndroid Build Coastguard Worker 199*387f9dfdSAndroid Build Coastguard Worker u16 family = sk->__sk_common.skc_family; 200*387f9dfdSAndroid Build Coastguard Worker 201*387f9dfdSAndroid Build Coastguard Worker FILTER_FAMILY 202*387f9dfdSAndroid Build Coastguard Worker 203*387f9dfdSAndroid Build Coastguard Worker if (family == AF_INET) { 204*387f9dfdSAndroid Build Coastguard Worker struct ipv4_data_t data4 = {}; 205*387f9dfdSAndroid Build Coastguard Worker data4.span_us = delta_us; 206*387f9dfdSAndroid Build Coastguard Worker data4.rx_b = rx_b; 207*387f9dfdSAndroid Build Coastguard Worker data4.tx_b = tx_b; 208*387f9dfdSAndroid Build Coastguard Worker data4.ts_us = bpf_ktime_get_ns() / 1000; 209*387f9dfdSAndroid Build Coastguard Worker data4.saddr = sk->__sk_common.skc_rcv_saddr; 210*387f9dfdSAndroid Build Coastguard Worker data4.daddr = sk->__sk_common.skc_daddr; 211*387f9dfdSAndroid Build Coastguard Worker // a workaround until data4 compiles with separate lport/dport 212*387f9dfdSAndroid Build Coastguard Worker data4.pid = pid; 213*387f9dfdSAndroid Build Coastguard Worker data4.ports = dport + ((0ULL + lport) << 32); 214*387f9dfdSAndroid Build Coastguard Worker if (mep == 0) { 215*387f9dfdSAndroid Build Coastguard Worker bpf_get_current_comm(&data4.task, sizeof(data4.task)); 216*387f9dfdSAndroid Build Coastguard Worker } else { 217*387f9dfdSAndroid Build Coastguard Worker bpf_probe_read_kernel(&data4.task, sizeof(data4.task), (void *)mep->task); 218*387f9dfdSAndroid Build Coastguard Worker } 219*387f9dfdSAndroid Build Coastguard Worker ipv4_events.perf_submit(ctx, &data4, sizeof(data4)); 220*387f9dfdSAndroid Build Coastguard Worker 221*387f9dfdSAndroid Build Coastguard Worker } else /* 6 */ { 222*387f9dfdSAndroid Build Coastguard Worker struct ipv6_data_t data6 = {}; 223*387f9dfdSAndroid Build Coastguard Worker data6.span_us = delta_us; 224*387f9dfdSAndroid Build Coastguard Worker data6.rx_b = rx_b; 225*387f9dfdSAndroid Build Coastguard Worker data6.tx_b = tx_b; 226*387f9dfdSAndroid Build Coastguard Worker data6.ts_us = bpf_ktime_get_ns() / 1000; 227*387f9dfdSAndroid Build Coastguard Worker bpf_probe_read_kernel(&data6.saddr, sizeof(data6.saddr), 228*387f9dfdSAndroid Build Coastguard Worker sk->__sk_common.skc_v6_rcv_saddr.in6_u.u6_addr32); 229*387f9dfdSAndroid Build Coastguard Worker bpf_probe_read_kernel(&data6.daddr, sizeof(data6.daddr), 230*387f9dfdSAndroid Build Coastguard Worker sk->__sk_common.skc_v6_daddr.in6_u.u6_addr32); 231*387f9dfdSAndroid Build Coastguard Worker // a workaround until data6 compiles with separate lport/dport 232*387f9dfdSAndroid Build Coastguard Worker data6.ports = dport + ((0ULL + lport) << 32); 233*387f9dfdSAndroid Build Coastguard Worker data6.pid = pid; 234*387f9dfdSAndroid Build Coastguard Worker if (mep == 0) { 235*387f9dfdSAndroid Build Coastguard Worker bpf_get_current_comm(&data6.task, sizeof(data6.task)); 236*387f9dfdSAndroid Build Coastguard Worker } else { 237*387f9dfdSAndroid Build Coastguard Worker bpf_probe_read_kernel(&data6.task, sizeof(data6.task), (void *)mep->task); 238*387f9dfdSAndroid Build Coastguard Worker } 239*387f9dfdSAndroid Build Coastguard Worker ipv6_events.perf_submit(ctx, &data6, sizeof(data6)); 240*387f9dfdSAndroid Build Coastguard Worker } 241*387f9dfdSAndroid Build Coastguard Worker 242*387f9dfdSAndroid Build Coastguard Worker if (mep != 0) 243*387f9dfdSAndroid Build Coastguard Worker whoami.delete(&sk); 244*387f9dfdSAndroid Build Coastguard Worker 245*387f9dfdSAndroid Build Coastguard Worker return 0; 246*387f9dfdSAndroid Build Coastguard Worker} 247*387f9dfdSAndroid Build Coastguard Worker""" 248*387f9dfdSAndroid Build Coastguard Worker 249*387f9dfdSAndroid Build Coastguard Workerbpf_text_tracepoint = """ 250*387f9dfdSAndroid Build Coastguard WorkerTRACEPOINT_PROBE(sock, inet_sock_set_state) 251*387f9dfdSAndroid Build Coastguard Worker{ 252*387f9dfdSAndroid Build Coastguard Worker if (args->protocol != IPPROTO_TCP) 253*387f9dfdSAndroid Build Coastguard Worker return 0; 254*387f9dfdSAndroid Build Coastguard Worker 255*387f9dfdSAndroid Build Coastguard Worker u32 pid = bpf_get_current_pid_tgid() >> 32; 256*387f9dfdSAndroid Build Coastguard Worker // sk is mostly used as a UUID, and for two tcp stats: 257*387f9dfdSAndroid Build Coastguard Worker struct sock *sk = (struct sock *)args->skaddr; 258*387f9dfdSAndroid Build Coastguard Worker 259*387f9dfdSAndroid Build Coastguard Worker // lport is either used in a filter here, or later 260*387f9dfdSAndroid Build Coastguard Worker u16 lport = args->sport; 261*387f9dfdSAndroid Build Coastguard Worker FILTER_LPORT 262*387f9dfdSAndroid Build Coastguard Worker 263*387f9dfdSAndroid Build Coastguard Worker // dport is either used in a filter here, or later 264*387f9dfdSAndroid Build Coastguard Worker u16 dport = args->dport; 265*387f9dfdSAndroid Build Coastguard Worker FILTER_DPORT 266*387f9dfdSAndroid Build Coastguard Worker 267*387f9dfdSAndroid Build Coastguard Worker /* 268*387f9dfdSAndroid Build Coastguard Worker * This tool includes PID and comm context. It's best effort, and may 269*387f9dfdSAndroid Build Coastguard Worker * be wrong in some situations. It currently works like this: 270*387f9dfdSAndroid Build Coastguard Worker * - record timestamp on any state < TCP_FIN_WAIT1 271*387f9dfdSAndroid Build Coastguard Worker * - cache task context on: 272*387f9dfdSAndroid Build Coastguard Worker * TCP_SYN_SENT: tracing from client 273*387f9dfdSAndroid Build Coastguard Worker * TCP_LAST_ACK: client-closed from server 274*387f9dfdSAndroid Build Coastguard Worker * - do output on TCP_CLOSE: 275*387f9dfdSAndroid Build Coastguard Worker * fetch task context if cached, or use current task 276*387f9dfdSAndroid Build Coastguard Worker */ 277*387f9dfdSAndroid Build Coastguard Worker 278*387f9dfdSAndroid Build Coastguard Worker // capture birth time 279*387f9dfdSAndroid Build Coastguard Worker if (args->newstate < TCP_FIN_WAIT1) { 280*387f9dfdSAndroid Build Coastguard Worker /* 281*387f9dfdSAndroid Build Coastguard Worker * Matching just ESTABLISHED may be sufficient, provided no code-path 282*387f9dfdSAndroid Build Coastguard Worker * sets ESTABLISHED without a tcp_set_state() call. Until we know 283*387f9dfdSAndroid Build Coastguard Worker * that for sure, match all early states to increase chances a 284*387f9dfdSAndroid Build Coastguard Worker * timestamp is set. 285*387f9dfdSAndroid Build Coastguard Worker * Note that this needs to be set before the PID filter later on, 286*387f9dfdSAndroid Build Coastguard Worker * since the PID isn't reliable for these early stages, so we must 287*387f9dfdSAndroid Build Coastguard Worker * save all timestamps and do the PID filter later when we can. 288*387f9dfdSAndroid Build Coastguard Worker */ 289*387f9dfdSAndroid Build Coastguard Worker u64 ts = bpf_ktime_get_ns(); 290*387f9dfdSAndroid Build Coastguard Worker birth.update(&sk, &ts); 291*387f9dfdSAndroid Build Coastguard Worker } 292*387f9dfdSAndroid Build Coastguard Worker 293*387f9dfdSAndroid Build Coastguard Worker // record PID & comm on SYN_SENT 294*387f9dfdSAndroid Build Coastguard Worker if (args->newstate == TCP_SYN_SENT || args->newstate == TCP_LAST_ACK) { 295*387f9dfdSAndroid Build Coastguard Worker // now we can PID filter, both here and a little later on for CLOSE 296*387f9dfdSAndroid Build Coastguard Worker FILTER_PID 297*387f9dfdSAndroid Build Coastguard Worker struct id_t me = {.pid = pid}; 298*387f9dfdSAndroid Build Coastguard Worker bpf_get_current_comm(&me.task, sizeof(me.task)); 299*387f9dfdSAndroid Build Coastguard Worker whoami.update(&sk, &me); 300*387f9dfdSAndroid Build Coastguard Worker } 301*387f9dfdSAndroid Build Coastguard Worker 302*387f9dfdSAndroid Build Coastguard Worker if (args->newstate != TCP_CLOSE) 303*387f9dfdSAndroid Build Coastguard Worker return 0; 304*387f9dfdSAndroid Build Coastguard Worker 305*387f9dfdSAndroid Build Coastguard Worker // calculate lifespan 306*387f9dfdSAndroid Build Coastguard Worker u64 *tsp, delta_us; 307*387f9dfdSAndroid Build Coastguard Worker tsp = birth.lookup(&sk); 308*387f9dfdSAndroid Build Coastguard Worker if (tsp == 0) { 309*387f9dfdSAndroid Build Coastguard Worker whoami.delete(&sk); // may not exist 310*387f9dfdSAndroid Build Coastguard Worker return 0; // missed create 311*387f9dfdSAndroid Build Coastguard Worker } 312*387f9dfdSAndroid Build Coastguard Worker delta_us = (bpf_ktime_get_ns() - *tsp) / 1000; 313*387f9dfdSAndroid Build Coastguard Worker birth.delete(&sk); 314*387f9dfdSAndroid Build Coastguard Worker 315*387f9dfdSAndroid Build Coastguard Worker // fetch possible cached data, and filter 316*387f9dfdSAndroid Build Coastguard Worker struct id_t *mep; 317*387f9dfdSAndroid Build Coastguard Worker mep = whoami.lookup(&sk); 318*387f9dfdSAndroid Build Coastguard Worker if (mep != 0) 319*387f9dfdSAndroid Build Coastguard Worker pid = mep->pid; 320*387f9dfdSAndroid Build Coastguard Worker FILTER_PID 321*387f9dfdSAndroid Build Coastguard Worker 322*387f9dfdSAndroid Build Coastguard Worker u16 family = args->family; 323*387f9dfdSAndroid Build Coastguard Worker FILTER_FAMILY 324*387f9dfdSAndroid Build Coastguard Worker 325*387f9dfdSAndroid Build Coastguard Worker // get throughput stats. see tcp_get_info(). 326*387f9dfdSAndroid Build Coastguard Worker u64 rx_b = 0, tx_b = 0; 327*387f9dfdSAndroid Build Coastguard Worker struct tcp_sock *tp = (struct tcp_sock *)sk; 328*387f9dfdSAndroid Build Coastguard Worker rx_b = tp->bytes_received; 329*387f9dfdSAndroid Build Coastguard Worker tx_b = tp->bytes_acked; 330*387f9dfdSAndroid Build Coastguard Worker 331*387f9dfdSAndroid Build Coastguard Worker if (args->family == AF_INET) { 332*387f9dfdSAndroid Build Coastguard Worker struct ipv4_data_t data4 = {}; 333*387f9dfdSAndroid Build Coastguard Worker data4.span_us = delta_us; 334*387f9dfdSAndroid Build Coastguard Worker data4.rx_b = rx_b; 335*387f9dfdSAndroid Build Coastguard Worker data4.tx_b = tx_b; 336*387f9dfdSAndroid Build Coastguard Worker data4.ts_us = bpf_ktime_get_ns() / 1000; 337*387f9dfdSAndroid Build Coastguard Worker __builtin_memcpy(&data4.saddr, args->saddr, sizeof(data4.saddr)); 338*387f9dfdSAndroid Build Coastguard Worker __builtin_memcpy(&data4.daddr, args->daddr, sizeof(data4.daddr)); 339*387f9dfdSAndroid Build Coastguard Worker // a workaround until data4 compiles with separate lport/dport 340*387f9dfdSAndroid Build Coastguard Worker data4.ports = dport + ((0ULL + lport) << 32); 341*387f9dfdSAndroid Build Coastguard Worker data4.pid = pid; 342*387f9dfdSAndroid Build Coastguard Worker 343*387f9dfdSAndroid Build Coastguard Worker if (mep == 0) { 344*387f9dfdSAndroid Build Coastguard Worker bpf_get_current_comm(&data4.task, sizeof(data4.task)); 345*387f9dfdSAndroid Build Coastguard Worker } else { 346*387f9dfdSAndroid Build Coastguard Worker bpf_probe_read_kernel(&data4.task, sizeof(data4.task), (void *)mep->task); 347*387f9dfdSAndroid Build Coastguard Worker } 348*387f9dfdSAndroid Build Coastguard Worker ipv4_events.perf_submit(args, &data4, sizeof(data4)); 349*387f9dfdSAndroid Build Coastguard Worker 350*387f9dfdSAndroid Build Coastguard Worker } else /* 6 */ { 351*387f9dfdSAndroid Build Coastguard Worker struct ipv6_data_t data6 = {}; 352*387f9dfdSAndroid Build Coastguard Worker data6.span_us = delta_us; 353*387f9dfdSAndroid Build Coastguard Worker data6.rx_b = rx_b; 354*387f9dfdSAndroid Build Coastguard Worker data6.tx_b = tx_b; 355*387f9dfdSAndroid Build Coastguard Worker data6.ts_us = bpf_ktime_get_ns() / 1000; 356*387f9dfdSAndroid Build Coastguard Worker __builtin_memcpy(&data6.saddr, args->saddr_v6, sizeof(data6.saddr)); 357*387f9dfdSAndroid Build Coastguard Worker __builtin_memcpy(&data6.daddr, args->daddr_v6, sizeof(data6.daddr)); 358*387f9dfdSAndroid Build Coastguard Worker // a workaround until data6 compiles with separate lport/dport 359*387f9dfdSAndroid Build Coastguard Worker data6.ports = dport + ((0ULL + lport) << 32); 360*387f9dfdSAndroid Build Coastguard Worker data6.pid = pid; 361*387f9dfdSAndroid Build Coastguard Worker if (mep == 0) { 362*387f9dfdSAndroid Build Coastguard Worker bpf_get_current_comm(&data6.task, sizeof(data6.task)); 363*387f9dfdSAndroid Build Coastguard Worker } else { 364*387f9dfdSAndroid Build Coastguard Worker bpf_probe_read_kernel(&data6.task, sizeof(data6.task), (void *)mep->task); 365*387f9dfdSAndroid Build Coastguard Worker } 366*387f9dfdSAndroid Build Coastguard Worker ipv6_events.perf_submit(args, &data6, sizeof(data6)); 367*387f9dfdSAndroid Build Coastguard Worker } 368*387f9dfdSAndroid Build Coastguard Worker 369*387f9dfdSAndroid Build Coastguard Worker if (mep != 0) 370*387f9dfdSAndroid Build Coastguard Worker whoami.delete(&sk); 371*387f9dfdSAndroid Build Coastguard Worker 372*387f9dfdSAndroid Build Coastguard Worker return 0; 373*387f9dfdSAndroid Build Coastguard Worker} 374*387f9dfdSAndroid Build Coastguard Worker""" 375*387f9dfdSAndroid Build Coastguard Worker 376*387f9dfdSAndroid Build Coastguard Workerif (BPF.tracepoint_exists("sock", "inet_sock_set_state")): 377*387f9dfdSAndroid Build Coastguard Worker bpf_text += bpf_text_tracepoint 378*387f9dfdSAndroid Build Coastguard Workerelse: 379*387f9dfdSAndroid Build Coastguard Worker bpf_text += bpf_text_kprobe 380*387f9dfdSAndroid Build Coastguard Worker 381*387f9dfdSAndroid Build Coastguard Worker# code substitutions 382*387f9dfdSAndroid Build Coastguard Workerif args.pid: 383*387f9dfdSAndroid Build Coastguard Worker bpf_text = bpf_text.replace('FILTER_PID', 384*387f9dfdSAndroid Build Coastguard Worker 'if (pid != %s) { return 0; }' % args.pid) 385*387f9dfdSAndroid Build Coastguard Workerif args.remoteport: 386*387f9dfdSAndroid Build Coastguard Worker dports = [int(dport) for dport in args.remoteport.split(',')] 387*387f9dfdSAndroid Build Coastguard Worker dports_if = ' && '.join(['dport != %d' % dport for dport in dports]) 388*387f9dfdSAndroid Build Coastguard Worker bpf_text = bpf_text.replace('FILTER_DPORT', 389*387f9dfdSAndroid Build Coastguard Worker 'if (%s) { birth.delete(&sk); return 0; }' % dports_if) 390*387f9dfdSAndroid Build Coastguard Workerif args.localport: 391*387f9dfdSAndroid Build Coastguard Worker lports = [int(lport) for lport in args.localport.split(',')] 392*387f9dfdSAndroid Build Coastguard Worker lports_if = ' && '.join(['lport != %d' % lport for lport in lports]) 393*387f9dfdSAndroid Build Coastguard Worker bpf_text = bpf_text.replace('FILTER_LPORT', 394*387f9dfdSAndroid Build Coastguard Worker 'if (%s) { birth.delete(&sk); return 0; }' % lports_if) 395*387f9dfdSAndroid Build Coastguard Workerif args.ipv4: 396*387f9dfdSAndroid Build Coastguard Worker bpf_text = bpf_text.replace('FILTER_FAMILY', 397*387f9dfdSAndroid Build Coastguard Worker 'if (family != AF_INET) { return 0; }') 398*387f9dfdSAndroid Build Coastguard Workerelif args.ipv6: 399*387f9dfdSAndroid Build Coastguard Worker bpf_text = bpf_text.replace('FILTER_FAMILY', 400*387f9dfdSAndroid Build Coastguard Worker 'if (family != AF_INET6) { return 0; }') 401*387f9dfdSAndroid Build Coastguard Workerbpf_text = bpf_text.replace('FILTER_PID', '') 402*387f9dfdSAndroid Build Coastguard Workerbpf_text = bpf_text.replace('FILTER_DPORT', '') 403*387f9dfdSAndroid Build Coastguard Workerbpf_text = bpf_text.replace('FILTER_LPORT', '') 404*387f9dfdSAndroid Build Coastguard Workerbpf_text = bpf_text.replace('FILTER_FAMILY', '') 405*387f9dfdSAndroid Build Coastguard Worker 406*387f9dfdSAndroid Build Coastguard Workerif debug or args.ebpf: 407*387f9dfdSAndroid Build Coastguard Worker print(bpf_text) 408*387f9dfdSAndroid Build Coastguard Worker if args.ebpf: 409*387f9dfdSAndroid Build Coastguard Worker exit() 410*387f9dfdSAndroid Build Coastguard Worker 411*387f9dfdSAndroid Build Coastguard Worker# 412*387f9dfdSAndroid Build Coastguard Worker# Setup output formats 413*387f9dfdSAndroid Build Coastguard Worker# 414*387f9dfdSAndroid Build Coastguard Worker# Don't change the default output (next 2 lines): this fits in 80 chars. I 415*387f9dfdSAndroid Build Coastguard Worker# know it doesn't have NS or UIDs etc. I know. If you really, really, really 416*387f9dfdSAndroid Build Coastguard Worker# need to add columns, columns that solve real actual problems, I'd start by 417*387f9dfdSAndroid Build Coastguard Worker# adding an extended mode (-x) to included those columns. 418*387f9dfdSAndroid Build Coastguard Worker# 419*387f9dfdSAndroid Build Coastguard Workerheader_string = "%-5s %-10.10s %s%-15s %-5s %-15s %-5s %5s %5s %s" 420*387f9dfdSAndroid Build Coastguard Workerformat_string = "%-5d %-10.10s %s%-15s %-5d %-15s %-5d %5d %5d %.2f" 421*387f9dfdSAndroid Build Coastguard Workerif args.wide: 422*387f9dfdSAndroid Build Coastguard Worker header_string = "%-5s %-16.16s %-2s %-39s %-5s %-39s %-5s %6s %6s %s" 423*387f9dfdSAndroid Build Coastguard Worker format_string = "%-5d %-16.16s %-2s %-39s %-5s %-39s %-5d %6d %6d %.2f" 424*387f9dfdSAndroid Build Coastguard Workerif args.csv: 425*387f9dfdSAndroid Build Coastguard Worker header_string = "%s,%s,%s,%s,%s,%s,%s,%s,%s,%s" 426*387f9dfdSAndroid Build Coastguard Worker format_string = "%d,%s,%s,%s,%s,%s,%d,%d,%d,%.2f" 427*387f9dfdSAndroid Build Coastguard Worker 428*387f9dfdSAndroid Build Coastguard Worker# process event 429*387f9dfdSAndroid Build Coastguard Workerdef print_ipv4_event(cpu, data, size): 430*387f9dfdSAndroid Build Coastguard Worker event = b["ipv4_events"].event(data) 431*387f9dfdSAndroid Build Coastguard Worker global start_ts 432*387f9dfdSAndroid Build Coastguard Worker if args.time: 433*387f9dfdSAndroid Build Coastguard Worker if args.csv: 434*387f9dfdSAndroid Build Coastguard Worker print("%s," % strftime("%H:%M:%S"), end="") 435*387f9dfdSAndroid Build Coastguard Worker else: 436*387f9dfdSAndroid Build Coastguard Worker print("%-8s " % strftime("%H:%M:%S"), end="") 437*387f9dfdSAndroid Build Coastguard Worker if args.timestamp: 438*387f9dfdSAndroid Build Coastguard Worker if start_ts == 0: 439*387f9dfdSAndroid Build Coastguard Worker start_ts = event.ts_us 440*387f9dfdSAndroid Build Coastguard Worker delta_s = (float(event.ts_us) - start_ts) / 1000000 441*387f9dfdSAndroid Build Coastguard Worker if args.csv: 442*387f9dfdSAndroid Build Coastguard Worker print("%.6f," % delta_s, end="") 443*387f9dfdSAndroid Build Coastguard Worker else: 444*387f9dfdSAndroid Build Coastguard Worker print("%-9.6f " % delta_s, end="") 445*387f9dfdSAndroid Build Coastguard Worker print(format_string % (event.pid, event.task.decode('utf-8', 'replace'), 446*387f9dfdSAndroid Build Coastguard Worker "4" if args.wide or args.csv else "", 447*387f9dfdSAndroid Build Coastguard Worker inet_ntop(AF_INET, pack("I", event.saddr)), event.ports >> 32, 448*387f9dfdSAndroid Build Coastguard Worker inet_ntop(AF_INET, pack("I", event.daddr)), event.ports & 0xffffffff, 449*387f9dfdSAndroid Build Coastguard Worker event.tx_b / 1024, event.rx_b / 1024, float(event.span_us) / 1000)) 450*387f9dfdSAndroid Build Coastguard Worker 451*387f9dfdSAndroid Build Coastguard Workerdef print_ipv6_event(cpu, data, size): 452*387f9dfdSAndroid Build Coastguard Worker event = b["ipv6_events"].event(data) 453*387f9dfdSAndroid Build Coastguard Worker global start_ts 454*387f9dfdSAndroid Build Coastguard Worker if args.time: 455*387f9dfdSAndroid Build Coastguard Worker if args.csv: 456*387f9dfdSAndroid Build Coastguard Worker print("%s," % strftime("%H:%M:%S"), end="") 457*387f9dfdSAndroid Build Coastguard Worker else: 458*387f9dfdSAndroid Build Coastguard Worker print("%-8s " % strftime("%H:%M:%S"), end="") 459*387f9dfdSAndroid Build Coastguard Worker if args.timestamp: 460*387f9dfdSAndroid Build Coastguard Worker if start_ts == 0: 461*387f9dfdSAndroid Build Coastguard Worker start_ts = event.ts_us 462*387f9dfdSAndroid Build Coastguard Worker delta_s = (float(event.ts_us) - start_ts) / 1000000 463*387f9dfdSAndroid Build Coastguard Worker if args.csv: 464*387f9dfdSAndroid Build Coastguard Worker print("%.6f," % delta_s, end="") 465*387f9dfdSAndroid Build Coastguard Worker else: 466*387f9dfdSAndroid Build Coastguard Worker print("%-9.6f " % delta_s, end="") 467*387f9dfdSAndroid Build Coastguard Worker print(format_string % (event.pid, event.task.decode('utf-8', 'replace'), 468*387f9dfdSAndroid Build Coastguard Worker "6" if args.wide or args.csv else "", 469*387f9dfdSAndroid Build Coastguard Worker inet_ntop(AF_INET6, event.saddr), event.ports >> 32, 470*387f9dfdSAndroid Build Coastguard Worker inet_ntop(AF_INET6, event.daddr), event.ports & 0xffffffff, 471*387f9dfdSAndroid Build Coastguard Worker event.tx_b / 1024, event.rx_b / 1024, float(event.span_us) / 1000)) 472*387f9dfdSAndroid Build Coastguard Worker 473*387f9dfdSAndroid Build Coastguard Worker# initialize BPF 474*387f9dfdSAndroid Build Coastguard Workerb = BPF(text=bpf_text) 475*387f9dfdSAndroid Build Coastguard Worker 476*387f9dfdSAndroid Build Coastguard Worker# header 477*387f9dfdSAndroid Build Coastguard Workerif args.time: 478*387f9dfdSAndroid Build Coastguard Worker if args.csv: 479*387f9dfdSAndroid Build Coastguard Worker print("%s," % ("TIME"), end="") 480*387f9dfdSAndroid Build Coastguard Worker else: 481*387f9dfdSAndroid Build Coastguard Worker print("%-8s " % ("TIME"), end="") 482*387f9dfdSAndroid Build Coastguard Workerif args.timestamp: 483*387f9dfdSAndroid Build Coastguard Worker if args.csv: 484*387f9dfdSAndroid Build Coastguard Worker print("%s," % ("TIME(s)"), end="") 485*387f9dfdSAndroid Build Coastguard Worker else: 486*387f9dfdSAndroid Build Coastguard Worker print("%-9s " % ("TIME(s)"), end="") 487*387f9dfdSAndroid Build Coastguard Workerprint(header_string % ("PID", "COMM", 488*387f9dfdSAndroid Build Coastguard Worker "IP" if args.wide or args.csv else "", "LADDR", 489*387f9dfdSAndroid Build Coastguard Worker "LPORT", "RADDR", "RPORT", "TX_KB", "RX_KB", "MS")) 490*387f9dfdSAndroid Build Coastguard Worker 491*387f9dfdSAndroid Build Coastguard Workerstart_ts = 0 492*387f9dfdSAndroid Build Coastguard Worker 493*387f9dfdSAndroid Build Coastguard Worker# read events 494*387f9dfdSAndroid Build Coastguard Workerb["ipv4_events"].open_perf_buffer(print_ipv4_event, page_cnt=64) 495*387f9dfdSAndroid Build Coastguard Workerb["ipv6_events"].open_perf_buffer(print_ipv6_event, page_cnt=64) 496*387f9dfdSAndroid Build Coastguard Workerwhile 1: 497*387f9dfdSAndroid Build Coastguard Worker try: 498*387f9dfdSAndroid Build Coastguard Worker b.perf_buffer_poll() 499*387f9dfdSAndroid Build Coastguard Worker except KeyboardInterrupt: 500*387f9dfdSAndroid Build Coastguard Worker exit() 501