xref: /aosp_15_r20/external/bcc/tools/tcptop.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# tcptop    Summarize TCP send/recv throughput by host.
5*387f9dfdSAndroid Build Coastguard Worker#           For Linux, uses BCC, eBPF. Embedded C.
6*387f9dfdSAndroid Build Coastguard Worker#
7*387f9dfdSAndroid Build Coastguard Worker# USAGE: tcptop [-h] [-C] [-S] [-p PID] [interval [count]] [-4 | -6]
8*387f9dfdSAndroid Build Coastguard Worker#
9*387f9dfdSAndroid Build Coastguard Worker# This uses dynamic tracing of kernel functions, and will need to be updated
10*387f9dfdSAndroid Build Coastguard Worker# to match kernel changes.
11*387f9dfdSAndroid Build Coastguard Worker#
12*387f9dfdSAndroid Build Coastguard Worker# WARNING: This traces all send/receives at the TCP level, and while it
13*387f9dfdSAndroid Build Coastguard Worker# summarizes data in-kernel to reduce overhead, there may still be some
14*387f9dfdSAndroid Build Coastguard Worker# overhead at high TCP send/receive rates (eg, ~13% of one CPU at 100k TCP
15*387f9dfdSAndroid Build Coastguard Worker# events/sec. This is not the same as packet rate: funccount can be used to
16*387f9dfdSAndroid Build Coastguard Worker# count the kprobes below to find out the TCP rate). Test in a lab environment
17*387f9dfdSAndroid Build Coastguard Worker# first. If your send/receive rate is low (eg, <1k/sec) then the overhead is
18*387f9dfdSAndroid Build Coastguard Worker# expected to be negligible.
19*387f9dfdSAndroid Build Coastguard Worker#
20*387f9dfdSAndroid Build Coastguard Worker# ToDo: Fit output to screen size (top X only) in default (not -C) mode.
21*387f9dfdSAndroid Build Coastguard Worker#
22*387f9dfdSAndroid Build Coastguard Worker# Copyright 2016 Netflix, Inc.
23*387f9dfdSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License")
24*387f9dfdSAndroid Build Coastguard Worker#
25*387f9dfdSAndroid Build Coastguard Worker# 02-Sep-2016   Brendan Gregg   Created this.
26*387f9dfdSAndroid Build Coastguard Worker
27*387f9dfdSAndroid Build Coastguard Workerfrom __future__ import print_function
28*387f9dfdSAndroid Build Coastguard Workerfrom bcc import BPF
29*387f9dfdSAndroid Build Coastguard Workerfrom bcc.containers import filter_by_containers
30*387f9dfdSAndroid Build Coastguard Workerimport argparse
31*387f9dfdSAndroid Build Coastguard Workerfrom socket import inet_ntop, AF_INET, AF_INET6
32*387f9dfdSAndroid Build Coastguard Workerfrom struct import pack
33*387f9dfdSAndroid Build Coastguard Workerfrom time import sleep, strftime
34*387f9dfdSAndroid Build Coastguard Workerfrom subprocess import call
35*387f9dfdSAndroid Build Coastguard Workerfrom collections import namedtuple, defaultdict
36*387f9dfdSAndroid Build Coastguard Worker
37*387f9dfdSAndroid Build Coastguard Worker# arguments
38*387f9dfdSAndroid Build Coastguard Workerdef range_check(string):
39*387f9dfdSAndroid Build Coastguard Worker    value = int(string)
40*387f9dfdSAndroid Build Coastguard Worker    if value < 1:
41*387f9dfdSAndroid Build Coastguard Worker        msg = "value must be stricly positive, got %d" % (value,)
42*387f9dfdSAndroid Build Coastguard Worker        raise argparse.ArgumentTypeError(msg)
43*387f9dfdSAndroid Build Coastguard Worker    return value
44*387f9dfdSAndroid Build Coastguard Worker
45*387f9dfdSAndroid Build Coastguard Workerexamples = """examples:
46*387f9dfdSAndroid Build Coastguard Worker    ./tcptop           # trace TCP send/recv by host
47*387f9dfdSAndroid Build Coastguard Worker    ./tcptop -C        # don't clear the screen
48*387f9dfdSAndroid Build Coastguard Worker    ./tcptop -p 181    # only trace PID 181
49*387f9dfdSAndroid Build Coastguard Worker    ./tcptop --cgroupmap mappath  # only trace cgroups in this BPF map
50*387f9dfdSAndroid Build Coastguard Worker    ./tcptop --mntnsmap mappath   # only trace mount namespaces in the map
51*387f9dfdSAndroid Build Coastguard Worker    ./tcptop -4        # trace IPv4 family only
52*387f9dfdSAndroid Build Coastguard Worker    ./tcptop -6        # trace IPv6 family only
53*387f9dfdSAndroid Build Coastguard Worker"""
54*387f9dfdSAndroid Build Coastguard Workerparser = argparse.ArgumentParser(
55*387f9dfdSAndroid Build Coastguard Worker    description="Summarize TCP send/recv throughput by host",
56*387f9dfdSAndroid Build Coastguard Worker    formatter_class=argparse.RawDescriptionHelpFormatter,
57*387f9dfdSAndroid Build Coastguard Worker    epilog=examples)
58*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-C", "--noclear", action="store_true",
59*387f9dfdSAndroid Build Coastguard Worker    help="don't clear the screen")
60*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-S", "--nosummary", action="store_true",
61*387f9dfdSAndroid Build Coastguard Worker    help="skip system summary line")
62*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-p", "--pid",
63*387f9dfdSAndroid Build Coastguard Worker    help="trace this PID only")
64*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("interval", nargs="?", default=1, type=range_check,
65*387f9dfdSAndroid Build Coastguard Worker    help="output interval, in seconds (default 1)")
66*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("count", nargs="?", default=-1, type=range_check,
67*387f9dfdSAndroid Build Coastguard Worker    help="number of outputs")
68*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("--cgroupmap",
69*387f9dfdSAndroid Build Coastguard Worker    help="trace cgroups in this BPF map only")
70*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("--mntnsmap",
71*387f9dfdSAndroid Build Coastguard Worker    help="trace mount namespaces in this BPF map only")
72*387f9dfdSAndroid Build Coastguard Workergroup = parser.add_mutually_exclusive_group()
73*387f9dfdSAndroid Build Coastguard Workergroup.add_argument("-4", "--ipv4", action="store_true",
74*387f9dfdSAndroid Build Coastguard Worker    help="trace IPv4 family only")
75*387f9dfdSAndroid Build Coastguard Workergroup.add_argument("-6", "--ipv6", action="store_true",
76*387f9dfdSAndroid Build Coastguard Worker    help="trace IPv6 family only")
77*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("--ebpf", action="store_true",
78*387f9dfdSAndroid Build Coastguard Worker    help=argparse.SUPPRESS)
79*387f9dfdSAndroid Build Coastguard Workerargs = parser.parse_args()
80*387f9dfdSAndroid Build Coastguard Workerdebug = 0
81*387f9dfdSAndroid Build Coastguard Worker
82*387f9dfdSAndroid Build Coastguard Worker# linux stats
83*387f9dfdSAndroid Build Coastguard Workerloadavg = "/proc/loadavg"
84*387f9dfdSAndroid Build Coastguard Worker
85*387f9dfdSAndroid Build Coastguard Worker# define BPF program
86*387f9dfdSAndroid Build Coastguard Workerbpf_text = """
87*387f9dfdSAndroid Build Coastguard Worker#include <uapi/linux/ptrace.h>
88*387f9dfdSAndroid Build Coastguard Worker#include <net/sock.h>
89*387f9dfdSAndroid Build Coastguard Worker#include <bcc/proto.h>
90*387f9dfdSAndroid Build Coastguard Worker
91*387f9dfdSAndroid Build Coastguard Workerstruct ipv4_key_t {
92*387f9dfdSAndroid Build Coastguard Worker    u32 pid;
93*387f9dfdSAndroid Build Coastguard Worker    char name[TASK_COMM_LEN];
94*387f9dfdSAndroid Build Coastguard Worker    u32 saddr;
95*387f9dfdSAndroid Build Coastguard Worker    u32 daddr;
96*387f9dfdSAndroid Build Coastguard Worker    u16 lport;
97*387f9dfdSAndroid Build Coastguard Worker    u16 dport;
98*387f9dfdSAndroid Build Coastguard Worker};
99*387f9dfdSAndroid Build Coastguard WorkerBPF_HASH(ipv4_send_bytes, struct ipv4_key_t);
100*387f9dfdSAndroid Build Coastguard WorkerBPF_HASH(ipv4_recv_bytes, struct ipv4_key_t);
101*387f9dfdSAndroid Build Coastguard Worker
102*387f9dfdSAndroid Build Coastguard Workerstruct ipv6_key_t {
103*387f9dfdSAndroid Build Coastguard Worker    unsigned __int128 saddr;
104*387f9dfdSAndroid Build Coastguard Worker    unsigned __int128 daddr;
105*387f9dfdSAndroid Build Coastguard Worker    u32 pid;
106*387f9dfdSAndroid Build Coastguard Worker    char name[TASK_COMM_LEN];
107*387f9dfdSAndroid Build Coastguard Worker    u16 lport;
108*387f9dfdSAndroid Build Coastguard Worker    u16 dport;
109*387f9dfdSAndroid Build Coastguard Worker    u64 __pad__;
110*387f9dfdSAndroid Build Coastguard Worker};
111*387f9dfdSAndroid Build Coastguard WorkerBPF_HASH(ipv6_send_bytes, struct ipv6_key_t);
112*387f9dfdSAndroid Build Coastguard WorkerBPF_HASH(ipv6_recv_bytes, struct ipv6_key_t);
113*387f9dfdSAndroid Build Coastguard WorkerBPF_HASH(sock_store, u32, struct sock *);
114*387f9dfdSAndroid Build Coastguard Worker
115*387f9dfdSAndroid Build Coastguard Workerstatic int tcp_sendstat(int size)
116*387f9dfdSAndroid Build Coastguard Worker{
117*387f9dfdSAndroid Build Coastguard Worker    if (container_should_be_filtered()) {
118*387f9dfdSAndroid Build Coastguard Worker        return 0;
119*387f9dfdSAndroid Build Coastguard Worker    }
120*387f9dfdSAndroid Build Coastguard Worker
121*387f9dfdSAndroid Build Coastguard Worker    u32 pid = bpf_get_current_pid_tgid() >> 32;
122*387f9dfdSAndroid Build Coastguard Worker    FILTER_PID
123*387f9dfdSAndroid Build Coastguard Worker    u32 tid = bpf_get_current_pid_tgid();
124*387f9dfdSAndroid Build Coastguard Worker    struct sock **sockpp;
125*387f9dfdSAndroid Build Coastguard Worker    sockpp = sock_store.lookup(&tid);
126*387f9dfdSAndroid Build Coastguard Worker    if (sockpp == 0) {
127*387f9dfdSAndroid Build Coastguard Worker        return 0; //miss the entry
128*387f9dfdSAndroid Build Coastguard Worker    }
129*387f9dfdSAndroid Build Coastguard Worker    struct sock *sk = *sockpp;
130*387f9dfdSAndroid Build Coastguard Worker    u16 dport = 0, family;
131*387f9dfdSAndroid Build Coastguard Worker    bpf_probe_read_kernel(&family, sizeof(family),
132*387f9dfdSAndroid Build Coastguard Worker        &sk->__sk_common.skc_family);
133*387f9dfdSAndroid Build Coastguard Worker    FILTER_FAMILY
134*387f9dfdSAndroid Build Coastguard Worker
135*387f9dfdSAndroid Build Coastguard Worker    if (family == AF_INET) {
136*387f9dfdSAndroid Build Coastguard Worker        struct ipv4_key_t ipv4_key = {.pid = pid};
137*387f9dfdSAndroid Build Coastguard Worker        bpf_get_current_comm(&ipv4_key.name, sizeof(ipv4_key.name));
138*387f9dfdSAndroid Build Coastguard Worker        bpf_probe_read_kernel(&ipv4_key.saddr, sizeof(ipv4_key.saddr),
139*387f9dfdSAndroid Build Coastguard Worker            &sk->__sk_common.skc_rcv_saddr);
140*387f9dfdSAndroid Build Coastguard Worker        bpf_probe_read_kernel(&ipv4_key.daddr, sizeof(ipv4_key.daddr),
141*387f9dfdSAndroid Build Coastguard Worker            &sk->__sk_common.skc_daddr);
142*387f9dfdSAndroid Build Coastguard Worker        bpf_probe_read_kernel(&ipv4_key.lport, sizeof(ipv4_key.lport),
143*387f9dfdSAndroid Build Coastguard Worker            &sk->__sk_common.skc_num);
144*387f9dfdSAndroid Build Coastguard Worker        bpf_probe_read_kernel(&dport, sizeof(dport),
145*387f9dfdSAndroid Build Coastguard Worker            &sk->__sk_common.skc_dport);
146*387f9dfdSAndroid Build Coastguard Worker        ipv4_key.dport = ntohs(dport);
147*387f9dfdSAndroid Build Coastguard Worker        ipv4_send_bytes.increment(ipv4_key, size);
148*387f9dfdSAndroid Build Coastguard Worker
149*387f9dfdSAndroid Build Coastguard Worker    } else if (family == AF_INET6) {
150*387f9dfdSAndroid Build Coastguard Worker        struct ipv6_key_t ipv6_key = {.pid = pid};
151*387f9dfdSAndroid Build Coastguard Worker        bpf_get_current_comm(&ipv6_key.name, sizeof(ipv6_key.name));
152*387f9dfdSAndroid Build Coastguard Worker        bpf_probe_read_kernel(&ipv6_key.saddr, sizeof(ipv6_key.saddr),
153*387f9dfdSAndroid Build Coastguard Worker            &sk->__sk_common.skc_v6_rcv_saddr.in6_u.u6_addr32);
154*387f9dfdSAndroid Build Coastguard Worker        bpf_probe_read_kernel(&ipv6_key.daddr, sizeof(ipv6_key.daddr),
155*387f9dfdSAndroid Build Coastguard Worker            &sk->__sk_common.skc_v6_daddr.in6_u.u6_addr32);
156*387f9dfdSAndroid Build Coastguard Worker        bpf_probe_read_kernel(&ipv6_key.lport, sizeof(ipv6_key.lport),
157*387f9dfdSAndroid Build Coastguard Worker            &sk->__sk_common.skc_num);
158*387f9dfdSAndroid Build Coastguard Worker        bpf_probe_read_kernel(&dport, sizeof(dport),
159*387f9dfdSAndroid Build Coastguard Worker            &sk->__sk_common.skc_dport);
160*387f9dfdSAndroid Build Coastguard Worker        ipv6_key.dport = ntohs(dport);
161*387f9dfdSAndroid Build Coastguard Worker        ipv6_send_bytes.increment(ipv6_key, size);
162*387f9dfdSAndroid Build Coastguard Worker    }
163*387f9dfdSAndroid Build Coastguard Worker    sock_store.delete(&tid);
164*387f9dfdSAndroid Build Coastguard Worker    // else drop
165*387f9dfdSAndroid Build Coastguard Worker
166*387f9dfdSAndroid Build Coastguard Worker    return 0;
167*387f9dfdSAndroid Build Coastguard Worker}
168*387f9dfdSAndroid Build Coastguard Worker
169*387f9dfdSAndroid Build Coastguard Workerint tcp_send_ret(struct pt_regs *ctx)
170*387f9dfdSAndroid Build Coastguard Worker{
171*387f9dfdSAndroid Build Coastguard Worker    int size = PT_REGS_RC(ctx);
172*387f9dfdSAndroid Build Coastguard Worker    if (size > 0)
173*387f9dfdSAndroid Build Coastguard Worker        return tcp_sendstat(size);
174*387f9dfdSAndroid Build Coastguard Worker    else
175*387f9dfdSAndroid Build Coastguard Worker        return 0;
176*387f9dfdSAndroid Build Coastguard Worker}
177*387f9dfdSAndroid Build Coastguard Worker
178*387f9dfdSAndroid Build Coastguard Workerint tcp_send_entry(struct pt_regs *ctx, struct sock *sk)
179*387f9dfdSAndroid Build Coastguard Worker{
180*387f9dfdSAndroid Build Coastguard Worker    if (container_should_be_filtered()) {
181*387f9dfdSAndroid Build Coastguard Worker        return 0;
182*387f9dfdSAndroid Build Coastguard Worker    }
183*387f9dfdSAndroid Build Coastguard Worker    u32 pid = bpf_get_current_pid_tgid() >> 32;
184*387f9dfdSAndroid Build Coastguard Worker    FILTER_PID
185*387f9dfdSAndroid Build Coastguard Worker    u32 tid = bpf_get_current_pid_tgid();
186*387f9dfdSAndroid Build Coastguard Worker    u16 family = sk->__sk_common.skc_family;
187*387f9dfdSAndroid Build Coastguard Worker    FILTER_FAMILY
188*387f9dfdSAndroid Build Coastguard Worker    sock_store.update(&tid, &sk);
189*387f9dfdSAndroid Build Coastguard Worker    return 0;
190*387f9dfdSAndroid Build Coastguard Worker}
191*387f9dfdSAndroid Build Coastguard Worker
192*387f9dfdSAndroid Build Coastguard Worker/*
193*387f9dfdSAndroid Build Coastguard Worker * tcp_recvmsg() would be obvious to trace, but is less suitable because:
194*387f9dfdSAndroid Build Coastguard Worker * - we'd need to trace both entry and return, to have both sock and size
195*387f9dfdSAndroid Build Coastguard Worker * - misses tcp_read_sock() traffic
196*387f9dfdSAndroid Build Coastguard Worker * we'd much prefer tracepoints once they are available.
197*387f9dfdSAndroid Build Coastguard Worker */
198*387f9dfdSAndroid Build Coastguard Workerint kprobe__tcp_cleanup_rbuf(struct pt_regs *ctx, struct sock *sk, int copied)
199*387f9dfdSAndroid Build Coastguard Worker{
200*387f9dfdSAndroid Build Coastguard Worker    if (container_should_be_filtered()) {
201*387f9dfdSAndroid Build Coastguard Worker        return 0;
202*387f9dfdSAndroid Build Coastguard Worker    }
203*387f9dfdSAndroid Build Coastguard Worker
204*387f9dfdSAndroid Build Coastguard Worker    u32 pid = bpf_get_current_pid_tgid() >> 32;
205*387f9dfdSAndroid Build Coastguard Worker    FILTER_PID
206*387f9dfdSAndroid Build Coastguard Worker
207*387f9dfdSAndroid Build Coastguard Worker    u16 dport = 0, family = sk->__sk_common.skc_family;
208*387f9dfdSAndroid Build Coastguard Worker    u64 *val, zero = 0;
209*387f9dfdSAndroid Build Coastguard Worker
210*387f9dfdSAndroid Build Coastguard Worker    if (copied <= 0)
211*387f9dfdSAndroid Build Coastguard Worker        return 0;
212*387f9dfdSAndroid Build Coastguard Worker
213*387f9dfdSAndroid Build Coastguard Worker    FILTER_FAMILY
214*387f9dfdSAndroid Build Coastguard Worker
215*387f9dfdSAndroid Build Coastguard Worker    if (family == AF_INET) {
216*387f9dfdSAndroid Build Coastguard Worker        struct ipv4_key_t ipv4_key = {.pid = pid};
217*387f9dfdSAndroid Build Coastguard Worker        bpf_get_current_comm(&ipv4_key.name, sizeof(ipv4_key.name));
218*387f9dfdSAndroid Build Coastguard Worker        ipv4_key.saddr = sk->__sk_common.skc_rcv_saddr;
219*387f9dfdSAndroid Build Coastguard Worker        ipv4_key.daddr = sk->__sk_common.skc_daddr;
220*387f9dfdSAndroid Build Coastguard Worker        ipv4_key.lport = sk->__sk_common.skc_num;
221*387f9dfdSAndroid Build Coastguard Worker        dport = sk->__sk_common.skc_dport;
222*387f9dfdSAndroid Build Coastguard Worker        ipv4_key.dport = ntohs(dport);
223*387f9dfdSAndroid Build Coastguard Worker        ipv4_recv_bytes.increment(ipv4_key, copied);
224*387f9dfdSAndroid Build Coastguard Worker
225*387f9dfdSAndroid Build Coastguard Worker    } else if (family == AF_INET6) {
226*387f9dfdSAndroid Build Coastguard Worker        struct ipv6_key_t ipv6_key = {.pid = pid};
227*387f9dfdSAndroid Build Coastguard Worker        bpf_get_current_comm(&ipv6_key.name, sizeof(ipv6_key.name));
228*387f9dfdSAndroid Build Coastguard Worker        bpf_probe_read_kernel(&ipv6_key.saddr, sizeof(ipv6_key.saddr),
229*387f9dfdSAndroid Build Coastguard Worker            &sk->__sk_common.skc_v6_rcv_saddr.in6_u.u6_addr32);
230*387f9dfdSAndroid Build Coastguard Worker        bpf_probe_read_kernel(&ipv6_key.daddr, sizeof(ipv6_key.daddr),
231*387f9dfdSAndroid Build Coastguard Worker            &sk->__sk_common.skc_v6_daddr.in6_u.u6_addr32);
232*387f9dfdSAndroid Build Coastguard Worker        ipv6_key.lport = sk->__sk_common.skc_num;
233*387f9dfdSAndroid Build Coastguard Worker        dport = sk->__sk_common.skc_dport;
234*387f9dfdSAndroid Build Coastguard Worker        ipv6_key.dport = ntohs(dport);
235*387f9dfdSAndroid Build Coastguard Worker        ipv6_recv_bytes.increment(ipv6_key, copied);
236*387f9dfdSAndroid Build Coastguard Worker    }
237*387f9dfdSAndroid Build Coastguard Worker    // else drop
238*387f9dfdSAndroid Build Coastguard Worker
239*387f9dfdSAndroid Build Coastguard Worker    return 0;
240*387f9dfdSAndroid Build Coastguard Worker}
241*387f9dfdSAndroid Build Coastguard Worker"""
242*387f9dfdSAndroid Build Coastguard Worker
243*387f9dfdSAndroid Build Coastguard Worker# code substitutions
244*387f9dfdSAndroid Build Coastguard Workerif args.pid:
245*387f9dfdSAndroid Build Coastguard Worker    bpf_text = bpf_text.replace('FILTER_PID',
246*387f9dfdSAndroid Build Coastguard Worker        'if (pid != %s) { return 0; }' % args.pid)
247*387f9dfdSAndroid Build Coastguard Workerelse:
248*387f9dfdSAndroid Build Coastguard Worker    bpf_text = bpf_text.replace('FILTER_PID', '')
249*387f9dfdSAndroid Build Coastguard Workerif args.ipv4:
250*387f9dfdSAndroid Build Coastguard Worker    bpf_text = bpf_text.replace('FILTER_FAMILY',
251*387f9dfdSAndroid Build Coastguard Worker        'if (family != AF_INET) { return 0; }')
252*387f9dfdSAndroid Build Coastguard Workerelif args.ipv6:
253*387f9dfdSAndroid Build Coastguard Worker    bpf_text = bpf_text.replace('FILTER_FAMILY',
254*387f9dfdSAndroid Build Coastguard Worker        'if (family != AF_INET6) { return 0; }')
255*387f9dfdSAndroid Build Coastguard Workerbpf_text = bpf_text.replace('FILTER_FAMILY', '')
256*387f9dfdSAndroid Build Coastguard Workerbpf_text = filter_by_containers(args) + bpf_text
257*387f9dfdSAndroid Build Coastguard Workerif debug or args.ebpf:
258*387f9dfdSAndroid Build Coastguard Worker    print(bpf_text)
259*387f9dfdSAndroid Build Coastguard Worker    if args.ebpf:
260*387f9dfdSAndroid Build Coastguard Worker        exit()
261*387f9dfdSAndroid Build Coastguard Worker
262*387f9dfdSAndroid Build Coastguard WorkerTCPSessionKey = namedtuple('TCPSession', ['pid', 'name', 'laddr', 'lport', 'daddr', 'dport'])
263*387f9dfdSAndroid Build Coastguard Worker
264*387f9dfdSAndroid Build Coastguard Workerdef get_ipv4_session_key(k):
265*387f9dfdSAndroid Build Coastguard Worker    return TCPSessionKey(pid=k.pid,
266*387f9dfdSAndroid Build Coastguard Worker                         name=k.name,
267*387f9dfdSAndroid Build Coastguard Worker                         laddr=inet_ntop(AF_INET, pack("I", k.saddr)),
268*387f9dfdSAndroid Build Coastguard Worker                         lport=k.lport,
269*387f9dfdSAndroid Build Coastguard Worker                         daddr=inet_ntop(AF_INET, pack("I", k.daddr)),
270*387f9dfdSAndroid Build Coastguard Worker                         dport=k.dport)
271*387f9dfdSAndroid Build Coastguard Worker
272*387f9dfdSAndroid Build Coastguard Workerdef get_ipv6_session_key(k):
273*387f9dfdSAndroid Build Coastguard Worker    return TCPSessionKey(pid=k.pid,
274*387f9dfdSAndroid Build Coastguard Worker                         name=k.name,
275*387f9dfdSAndroid Build Coastguard Worker                         laddr=inet_ntop(AF_INET6, k.saddr),
276*387f9dfdSAndroid Build Coastguard Worker                         lport=k.lport,
277*387f9dfdSAndroid Build Coastguard Worker                         daddr=inet_ntop(AF_INET6, k.daddr),
278*387f9dfdSAndroid Build Coastguard Worker                         dport=k.dport)
279*387f9dfdSAndroid Build Coastguard Worker
280*387f9dfdSAndroid Build Coastguard Worker# initialize BPF
281*387f9dfdSAndroid Build Coastguard Workerb = BPF(text=bpf_text)
282*387f9dfdSAndroid Build Coastguard Worker
283*387f9dfdSAndroid Build Coastguard Workerb.attach_kprobe(event='tcp_sendmsg', fn_name='tcp_send_entry')
284*387f9dfdSAndroid Build Coastguard Workerb.attach_kretprobe(event='tcp_sendmsg', fn_name='tcp_send_ret')
285*387f9dfdSAndroid Build Coastguard Workerif BPF.get_kprobe_functions(b'tcp_sendpage'):
286*387f9dfdSAndroid Build Coastguard Worker    b.attach_kprobe(event='tcp_sendpage', fn_name='tcp_send_entry')
287*387f9dfdSAndroid Build Coastguard Worker    b.attach_kretprobe(event='tcp_sendpage', fn_name='tcp_send_ret')
288*387f9dfdSAndroid Build Coastguard Worker
289*387f9dfdSAndroid Build Coastguard Workeripv4_send_bytes = b["ipv4_send_bytes"]
290*387f9dfdSAndroid Build Coastguard Workeripv4_recv_bytes = b["ipv4_recv_bytes"]
291*387f9dfdSAndroid Build Coastguard Workeripv6_send_bytes = b["ipv6_send_bytes"]
292*387f9dfdSAndroid Build Coastguard Workeripv6_recv_bytes = b["ipv6_recv_bytes"]
293*387f9dfdSAndroid Build Coastguard Worker
294*387f9dfdSAndroid Build Coastguard Workerprint('Tracing... Output every %s secs. Hit Ctrl-C to end' % args.interval)
295*387f9dfdSAndroid Build Coastguard Worker
296*387f9dfdSAndroid Build Coastguard Worker# output
297*387f9dfdSAndroid Build Coastguard Workeri = 0
298*387f9dfdSAndroid Build Coastguard Workerexiting = False
299*387f9dfdSAndroid Build Coastguard Workerwhile i != args.count and not exiting:
300*387f9dfdSAndroid Build Coastguard Worker    try:
301*387f9dfdSAndroid Build Coastguard Worker        sleep(args.interval)
302*387f9dfdSAndroid Build Coastguard Worker    except KeyboardInterrupt:
303*387f9dfdSAndroid Build Coastguard Worker        exiting = True
304*387f9dfdSAndroid Build Coastguard Worker
305*387f9dfdSAndroid Build Coastguard Worker    # header
306*387f9dfdSAndroid Build Coastguard Worker    if args.noclear:
307*387f9dfdSAndroid Build Coastguard Worker        print()
308*387f9dfdSAndroid Build Coastguard Worker    else:
309*387f9dfdSAndroid Build Coastguard Worker        call("clear")
310*387f9dfdSAndroid Build Coastguard Worker    if not args.nosummary:
311*387f9dfdSAndroid Build Coastguard Worker        with open(loadavg) as stats:
312*387f9dfdSAndroid Build Coastguard Worker            print("%-8s loadavg: %s" % (strftime("%H:%M:%S"), stats.read()))
313*387f9dfdSAndroid Build Coastguard Worker
314*387f9dfdSAndroid Build Coastguard Worker    # IPv4: build dict of all seen keys
315*387f9dfdSAndroid Build Coastguard Worker    ipv4_throughput = defaultdict(lambda: [0, 0])
316*387f9dfdSAndroid Build Coastguard Worker    for k, v in ipv4_send_bytes.items():
317*387f9dfdSAndroid Build Coastguard Worker        key = get_ipv4_session_key(k)
318*387f9dfdSAndroid Build Coastguard Worker        ipv4_throughput[key][0] = v.value
319*387f9dfdSAndroid Build Coastguard Worker    ipv4_send_bytes.clear()
320*387f9dfdSAndroid Build Coastguard Worker
321*387f9dfdSAndroid Build Coastguard Worker    for k, v in ipv4_recv_bytes.items():
322*387f9dfdSAndroid Build Coastguard Worker        key = get_ipv4_session_key(k)
323*387f9dfdSAndroid Build Coastguard Worker        ipv4_throughput[key][1] = v.value
324*387f9dfdSAndroid Build Coastguard Worker    ipv4_recv_bytes.clear()
325*387f9dfdSAndroid Build Coastguard Worker
326*387f9dfdSAndroid Build Coastguard Worker    if ipv4_throughput:
327*387f9dfdSAndroid Build Coastguard Worker        print("%-7s %-12s %-21s %-21s %6s %6s" % ("PID", "COMM",
328*387f9dfdSAndroid Build Coastguard Worker            "LADDR", "RADDR", "RX_KB", "TX_KB"))
329*387f9dfdSAndroid Build Coastguard Worker
330*387f9dfdSAndroid Build Coastguard Worker    # output
331*387f9dfdSAndroid Build Coastguard Worker    for k, (send_bytes, recv_bytes) in sorted(ipv4_throughput.items(),
332*387f9dfdSAndroid Build Coastguard Worker                                              key=lambda kv: sum(kv[1]),
333*387f9dfdSAndroid Build Coastguard Worker                                              reverse=True):
334*387f9dfdSAndroid Build Coastguard Worker        print("%-7d %-12.12s %-21s %-21s %6d %6d" % (k.pid,
335*387f9dfdSAndroid Build Coastguard Worker            k.name,
336*387f9dfdSAndroid Build Coastguard Worker            k.laddr + ":" + str(k.lport),
337*387f9dfdSAndroid Build Coastguard Worker            k.daddr + ":" + str(k.dport),
338*387f9dfdSAndroid Build Coastguard Worker            int(recv_bytes / 1024), int(send_bytes / 1024)))
339*387f9dfdSAndroid Build Coastguard Worker
340*387f9dfdSAndroid Build Coastguard Worker    # IPv6: build dict of all seen keys
341*387f9dfdSAndroid Build Coastguard Worker    ipv6_throughput = defaultdict(lambda: [0, 0])
342*387f9dfdSAndroid Build Coastguard Worker    for k, v in ipv6_send_bytes.items():
343*387f9dfdSAndroid Build Coastguard Worker        key = get_ipv6_session_key(k)
344*387f9dfdSAndroid Build Coastguard Worker        ipv6_throughput[key][0] = v.value
345*387f9dfdSAndroid Build Coastguard Worker    ipv6_send_bytes.clear()
346*387f9dfdSAndroid Build Coastguard Worker
347*387f9dfdSAndroid Build Coastguard Worker    for k, v in ipv6_recv_bytes.items():
348*387f9dfdSAndroid Build Coastguard Worker        key = get_ipv6_session_key(k)
349*387f9dfdSAndroid Build Coastguard Worker        ipv6_throughput[key][1] = v.value
350*387f9dfdSAndroid Build Coastguard Worker    ipv6_recv_bytes.clear()
351*387f9dfdSAndroid Build Coastguard Worker
352*387f9dfdSAndroid Build Coastguard Worker    if ipv6_throughput:
353*387f9dfdSAndroid Build Coastguard Worker        # more than 80 chars, sadly.
354*387f9dfdSAndroid Build Coastguard Worker        print("\n%-7s %-12s %-32s %-32s %6s %6s" % ("PID", "COMM",
355*387f9dfdSAndroid Build Coastguard Worker            "LADDR6", "RADDR6", "RX_KB", "TX_KB"))
356*387f9dfdSAndroid Build Coastguard Worker
357*387f9dfdSAndroid Build Coastguard Worker    # output
358*387f9dfdSAndroid Build Coastguard Worker    for k, (send_bytes, recv_bytes) in sorted(ipv6_throughput.items(),
359*387f9dfdSAndroid Build Coastguard Worker                                              key=lambda kv: sum(kv[1]),
360*387f9dfdSAndroid Build Coastguard Worker                                              reverse=True):
361*387f9dfdSAndroid Build Coastguard Worker        print("%-7d %-12.12s %-32s %-32s %6d %6d" % (k.pid,
362*387f9dfdSAndroid Build Coastguard Worker            k.name,
363*387f9dfdSAndroid Build Coastguard Worker            k.laddr + ":" + str(k.lport),
364*387f9dfdSAndroid Build Coastguard Worker            k.daddr + ":" + str(k.dport),
365*387f9dfdSAndroid Build Coastguard Worker            int(recv_bytes / 1024), int(send_bytes / 1024)))
366*387f9dfdSAndroid Build Coastguard Worker
367*387f9dfdSAndroid Build Coastguard Worker    i += 1
368