xref: /aosp_15_r20/external/bcc/tools/tcplife.lua (revision 387f9dfdfa2baef462e92476d413c7bc2470293e)
1*387f9dfdSAndroid Build Coastguard Worker#!/usr/bin/env bcc-lua
2*387f9dfdSAndroid Build Coastguard Worker--[[
3*387f9dfdSAndroid Build Coastguard WorkerLicensed under the Apache License, Version 2.0 (the "License");
4*387f9dfdSAndroid Build Coastguard Workeryou may not use this file except in compliance with the License.
5*387f9dfdSAndroid Build Coastguard WorkerYou may obtain a copy of the License at
6*387f9dfdSAndroid Build Coastguard Worker
7*387f9dfdSAndroid Build Coastguard Workerhttp://www.apache.org/licenses/LICENSE-2.0
8*387f9dfdSAndroid Build Coastguard Worker
9*387f9dfdSAndroid Build Coastguard WorkerUnless required by applicable law or agreed to in writing, software
10*387f9dfdSAndroid Build Coastguard Workerdistributed under the License is distributed on an "AS IS" BASIS,
11*387f9dfdSAndroid Build Coastguard WorkerWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*387f9dfdSAndroid Build Coastguard WorkerSee the License for the specific language governing permissions and
13*387f9dfdSAndroid Build Coastguard Workerlimitations under the License.
14*387f9dfdSAndroid Build Coastguard Worker
15*387f9dfdSAndroid Build Coastguard Worker18-Mar-2017  Simon Liu Created this.
16*387f9dfdSAndroid Build Coastguard Worker--]]
17*387f9dfdSAndroid Build Coastguard Worker
18*387f9dfdSAndroid Build Coastguard Workerlocal ffi = require("ffi")
19*387f9dfdSAndroid Build Coastguard Workerlocal bit = require("bit")
20*387f9dfdSAndroid Build Coastguard Worker
21*387f9dfdSAndroid Build Coastguard Workerffi.cdef[[
22*387f9dfdSAndroid Build Coastguard Workerconst char *inet_ntop(int af, const void *src, char *dst, int size);
23*387f9dfdSAndroid Build Coastguard Workeruint16_t ntohs(uint16_t netshort);
24*387f9dfdSAndroid Build Coastguard Worker]]
25*387f9dfdSAndroid Build Coastguard Worker
26*387f9dfdSAndroid Build Coastguard Workerlocal program = [[
27*387f9dfdSAndroid Build Coastguard Worker#include <uapi/linux/ptrace.h>
28*387f9dfdSAndroid Build Coastguard Worker#include <linux/tcp.h>
29*387f9dfdSAndroid Build Coastguard Worker#include <net/sock.h>
30*387f9dfdSAndroid Build Coastguard Worker#include <bcc/proto.h>
31*387f9dfdSAndroid Build Coastguard Worker
32*387f9dfdSAndroid Build Coastguard WorkerBPF_HASH(birth, struct sock *, u64);
33*387f9dfdSAndroid Build Coastguard Worker
34*387f9dfdSAndroid Build Coastguard Worker// separate data structs for ipv4 and ipv6
35*387f9dfdSAndroid Build Coastguard Workerstruct ipv4_data_t {
36*387f9dfdSAndroid Build Coastguard Worker    // XXX: switch some to u32's when supported
37*387f9dfdSAndroid Build Coastguard Worker    u64 ts_us;
38*387f9dfdSAndroid Build Coastguard Worker    u64 pid;
39*387f9dfdSAndroid Build Coastguard Worker    u64 saddr;
40*387f9dfdSAndroid Build Coastguard Worker    u64 daddr;
41*387f9dfdSAndroid Build Coastguard Worker    u64 ports;
42*387f9dfdSAndroid Build Coastguard Worker    u64 rx_b;
43*387f9dfdSAndroid Build Coastguard Worker    u64 tx_b;
44*387f9dfdSAndroid Build Coastguard Worker    u64 span_us;
45*387f9dfdSAndroid Build Coastguard Worker    char task[TASK_COMM_LEN];
46*387f9dfdSAndroid Build Coastguard Worker};
47*387f9dfdSAndroid Build Coastguard WorkerBPF_PERF_OUTPUT(ipv4_events);
48*387f9dfdSAndroid Build Coastguard Worker
49*387f9dfdSAndroid Build Coastguard Workerstruct ipv6_data_t {
50*387f9dfdSAndroid Build Coastguard Worker    u64 ts_us;
51*387f9dfdSAndroid Build Coastguard Worker    u64 pid;
52*387f9dfdSAndroid Build Coastguard Worker    u64 saddr[2];
53*387f9dfdSAndroid Build Coastguard Worker    u64 daddr[2];
54*387f9dfdSAndroid Build Coastguard Worker    u64 ports;
55*387f9dfdSAndroid Build Coastguard Worker    u64 rx_b;
56*387f9dfdSAndroid Build Coastguard Worker    u64 tx_b;
57*387f9dfdSAndroid Build Coastguard Worker    u64 span_us;
58*387f9dfdSAndroid Build Coastguard Worker    char task[TASK_COMM_LEN];
59*387f9dfdSAndroid Build Coastguard Worker};
60*387f9dfdSAndroid Build Coastguard WorkerBPF_PERF_OUTPUT(ipv6_events);
61*387f9dfdSAndroid Build Coastguard Worker
62*387f9dfdSAndroid Build Coastguard Workerstruct id_t {
63*387f9dfdSAndroid Build Coastguard Worker    u32 pid;
64*387f9dfdSAndroid Build Coastguard Worker    char task[TASK_COMM_LEN];
65*387f9dfdSAndroid Build Coastguard Worker};
66*387f9dfdSAndroid Build Coastguard WorkerBPF_HASH(whoami, struct sock *, struct id_t);
67*387f9dfdSAndroid Build Coastguard Worker
68*387f9dfdSAndroid Build Coastguard Workerint trace_tcp_set_state(struct pt_regs *ctx, struct sock *sk, int state)
69*387f9dfdSAndroid Build Coastguard Worker{
70*387f9dfdSAndroid Build Coastguard Worker    bpf_trace_printk("tcp_set_stat");
71*387f9dfdSAndroid Build Coastguard Worker    u32 pid = bpf_get_current_pid_tgid() >> 32;
72*387f9dfdSAndroid Build Coastguard Worker
73*387f9dfdSAndroid Build Coastguard Worker    // lport is either used in a filter here, or later
74*387f9dfdSAndroid Build Coastguard Worker    u16 lport = sk->__sk_common.skc_num;
75*387f9dfdSAndroid Build Coastguard Worker    FILTER_LPORT
76*387f9dfdSAndroid Build Coastguard Worker
77*387f9dfdSAndroid Build Coastguard Worker    // dport is either used in a filter here, or later
78*387f9dfdSAndroid Build Coastguard Worker    u16 dport = sk->__sk_common.skc_dport;
79*387f9dfdSAndroid Build Coastguard Worker    FILTER_DPORT
80*387f9dfdSAndroid Build Coastguard Worker
81*387f9dfdSAndroid Build Coastguard Worker    /*
82*387f9dfdSAndroid Build Coastguard Worker     * This tool includes PID and comm context. It's best effort, and may
83*387f9dfdSAndroid Build Coastguard Worker     * be wrong in some situations. It currently works like this:
84*387f9dfdSAndroid Build Coastguard Worker     * - record timestamp on any state < TCP_FIN_WAIT1
85*387f9dfdSAndroid Build Coastguard Worker     * - cache task context on:
86*387f9dfdSAndroid Build Coastguard Worker     *       TCP_SYN_SENT: tracing from client
87*387f9dfdSAndroid Build Coastguard Worker     *       TCP_LAST_ACK: client-closed from server
88*387f9dfdSAndroid Build Coastguard Worker     * - do output on TCP_CLOSE:
89*387f9dfdSAndroid Build Coastguard Worker     *       fetch task context if cached, or use current task
90*387f9dfdSAndroid Build Coastguard Worker     */
91*387f9dfdSAndroid Build Coastguard Worker
92*387f9dfdSAndroid Build Coastguard Worker    // capture birth time
93*387f9dfdSAndroid Build Coastguard Worker    if (state < TCP_FIN_WAIT1) {
94*387f9dfdSAndroid Build Coastguard Worker        /*
95*387f9dfdSAndroid Build Coastguard Worker         * Matching just ESTABLISHED may be sufficient, provided no code-path
96*387f9dfdSAndroid Build Coastguard Worker         * sets ESTABLISHED without a tcp_set_state() call. Until we know
97*387f9dfdSAndroid Build Coastguard Worker         * that for sure, match all early states to increase chances a
98*387f9dfdSAndroid Build Coastguard Worker         * timestamp is set.
99*387f9dfdSAndroid Build Coastguard Worker         * Note that this needs to be set before the PID filter later on,
100*387f9dfdSAndroid Build Coastguard Worker         * since the PID isn't reliable for these early stages, so we must
101*387f9dfdSAndroid Build Coastguard Worker         * save all timestamps and do the PID filter later when we can.
102*387f9dfdSAndroid Build Coastguard Worker         */
103*387f9dfdSAndroid Build Coastguard Worker        u64 ts = bpf_ktime_get_ns();
104*387f9dfdSAndroid Build Coastguard Worker        birth.update(&sk, &ts);
105*387f9dfdSAndroid Build Coastguard Worker    }
106*387f9dfdSAndroid Build Coastguard Worker
107*387f9dfdSAndroid Build Coastguard Worker    // record PID & comm on SYN_SENT
108*387f9dfdSAndroid Build Coastguard Worker    if (state == TCP_SYN_SENT || state == TCP_LAST_ACK) {
109*387f9dfdSAndroid Build Coastguard Worker        // now we can PID filter, both here and a little later on for CLOSE
110*387f9dfdSAndroid Build Coastguard Worker        FILTER_PID
111*387f9dfdSAndroid Build Coastguard Worker        struct id_t me = {.pid = pid};
112*387f9dfdSAndroid Build Coastguard Worker        bpf_get_current_comm(&me.task, sizeof(me.task));
113*387f9dfdSAndroid Build Coastguard Worker        whoami.update(&sk, &me);
114*387f9dfdSAndroid Build Coastguard Worker    }
115*387f9dfdSAndroid Build Coastguard Worker
116*387f9dfdSAndroid Build Coastguard Worker    if (state != TCP_CLOSE)
117*387f9dfdSAndroid Build Coastguard Worker        return 0;
118*387f9dfdSAndroid Build Coastguard Worker
119*387f9dfdSAndroid Build Coastguard Worker    // calculate lifespan
120*387f9dfdSAndroid Build Coastguard Worker    u64 *tsp, delta_us;
121*387f9dfdSAndroid Build Coastguard Worker    tsp = birth.lookup(&sk);
122*387f9dfdSAndroid Build Coastguard Worker    if (tsp == 0) {
123*387f9dfdSAndroid Build Coastguard Worker        whoami.delete(&sk);     // may not exist
124*387f9dfdSAndroid Build Coastguard Worker        return 0;               // missed create
125*387f9dfdSAndroid Build Coastguard Worker    }
126*387f9dfdSAndroid Build Coastguard Worker    delta_us = (bpf_ktime_get_ns() - *tsp) / 1000;
127*387f9dfdSAndroid Build Coastguard Worker    birth.delete(&sk);
128*387f9dfdSAndroid Build Coastguard Worker
129*387f9dfdSAndroid Build Coastguard Worker    // fetch possible cached data, and filter
130*387f9dfdSAndroid Build Coastguard Worker    struct id_t *mep;
131*387f9dfdSAndroid Build Coastguard Worker    mep = whoami.lookup(&sk);
132*387f9dfdSAndroid Build Coastguard Worker    if (mep != 0)
133*387f9dfdSAndroid Build Coastguard Worker        pid = mep->pid;
134*387f9dfdSAndroid Build Coastguard Worker    FILTER_PID
135*387f9dfdSAndroid Build Coastguard Worker
136*387f9dfdSAndroid Build Coastguard Worker    // get throughput stats. see tcp_get_info().
137*387f9dfdSAndroid Build Coastguard Worker    u64 rx_b = 0, tx_b = 0, sport = 0;
138*387f9dfdSAndroid Build Coastguard Worker    struct tcp_sock *tp = (struct tcp_sock *)sk;
139*387f9dfdSAndroid Build Coastguard Worker    rx_b = tp->bytes_received;
140*387f9dfdSAndroid Build Coastguard Worker    tx_b = tp->bytes_acked;
141*387f9dfdSAndroid Build Coastguard Worker
142*387f9dfdSAndroid Build Coastguard Worker    u16 family = sk->__sk_common.skc_family;
143*387f9dfdSAndroid Build Coastguard Worker
144*387f9dfdSAndroid Build Coastguard Worker    if (family == AF_INET) {
145*387f9dfdSAndroid Build Coastguard Worker        struct ipv4_data_t data4 = {.span_us = delta_us,
146*387f9dfdSAndroid Build Coastguard Worker            .rx_b = rx_b, .tx_b = tx_b};
147*387f9dfdSAndroid Build Coastguard Worker        data4.ts_us = bpf_ktime_get_ns() / 1000;
148*387f9dfdSAndroid Build Coastguard Worker        data4.saddr = sk->__sk_common.skc_rcv_saddr;
149*387f9dfdSAndroid Build Coastguard Worker        data4.daddr = sk->__sk_common.skc_daddr;
150*387f9dfdSAndroid Build Coastguard Worker        // a workaround until data4 compiles with separate lport/dport
151*387f9dfdSAndroid Build Coastguard Worker        data4.pid = pid;
152*387f9dfdSAndroid Build Coastguard Worker        data4.ports = ntohs(dport) + ((0ULL + lport) << 32);
153*387f9dfdSAndroid Build Coastguard Worker        if (mep == 0) {
154*387f9dfdSAndroid Build Coastguard Worker            bpf_get_current_comm(&data4.task, sizeof(data4.task));
155*387f9dfdSAndroid Build Coastguard Worker        } else {
156*387f9dfdSAndroid Build Coastguard Worker            bpf_probe_read_kernel(&data4.task, sizeof(data4.task), (void *)mep->task);
157*387f9dfdSAndroid Build Coastguard Worker        }
158*387f9dfdSAndroid Build Coastguard Worker        ipv4_events.perf_submit(ctx, &data4, sizeof(data4));
159*387f9dfdSAndroid Build Coastguard Worker
160*387f9dfdSAndroid Build Coastguard Worker    } else /* 6 */ {
161*387f9dfdSAndroid Build Coastguard Worker        struct ipv6_data_t data6 = {.span_us = delta_us,
162*387f9dfdSAndroid Build Coastguard Worker            .rx_b = rx_b, .tx_b = tx_b};
163*387f9dfdSAndroid Build Coastguard Worker        data6.ts_us = bpf_ktime_get_ns() / 1000;
164*387f9dfdSAndroid Build Coastguard Worker        bpf_probe_read_kernel(&data6.saddr, sizeof(data6.saddr),
165*387f9dfdSAndroid Build Coastguard Worker            sk->__sk_common.skc_v6_rcv_saddr.in6_u.u6_addr32);
166*387f9dfdSAndroid Build Coastguard Worker        bpf_probe_read_kernel(&data6.daddr, sizeof(data6.daddr),
167*387f9dfdSAndroid Build Coastguard Worker            sk->__sk_common.skc_v6_daddr.in6_u.u6_addr32);
168*387f9dfdSAndroid Build Coastguard Worker        // a workaround until data6 compiles with separate lport/dport
169*387f9dfdSAndroid Build Coastguard Worker        data6.ports = ntohs(dport) + ((0ULL + lport) << 32);
170*387f9dfdSAndroid Build Coastguard Worker        data6.pid = pid;
171*387f9dfdSAndroid Build Coastguard Worker        if (mep == 0) {
172*387f9dfdSAndroid Build Coastguard Worker            bpf_get_current_comm(&data6.task, sizeof(data6.task));
173*387f9dfdSAndroid Build Coastguard Worker        } else {
174*387f9dfdSAndroid Build Coastguard Worker            bpf_probe_read_kernel(&data6.task, sizeof(data6.task), (void *)mep->task);
175*387f9dfdSAndroid Build Coastguard Worker        }
176*387f9dfdSAndroid Build Coastguard Worker        ipv6_events.perf_submit(ctx, &data6, sizeof(data6));
177*387f9dfdSAndroid Build Coastguard Worker    }
178*387f9dfdSAndroid Build Coastguard Worker
179*387f9dfdSAndroid Build Coastguard Worker    if (mep != 0)
180*387f9dfdSAndroid Build Coastguard Worker        whoami.delete(&sk);
181*387f9dfdSAndroid Build Coastguard Worker
182*387f9dfdSAndroid Build Coastguard Worker    return 0;
183*387f9dfdSAndroid Build Coastguard Worker}
184*387f9dfdSAndroid Build Coastguard Worker]]
185*387f9dfdSAndroid Build Coastguard Worker
186*387f9dfdSAndroid Build Coastguard Workerlocal debug = false
187*387f9dfdSAndroid Build Coastguard Workerlocal start_ts = 0
188*387f9dfdSAndroid Build Coastguard Worker
189*387f9dfdSAndroid Build Coastguard Workerlocal inet_addresslen = #"255.255.255.255"
190*387f9dfdSAndroid Build Coastguard Workerlocal inet6_addresslen = #"ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"
191*387f9dfdSAndroid Build Coastguard Workerlocal AF_INET = 2
192*387f9dfdSAndroid Build Coastguard Workerlocal AF_INET6 = 10
193*387f9dfdSAndroid Build Coastguard Worker
194*387f9dfdSAndroid Build Coastguard Workerlocal header_string = "%-5s %-10.10s %s%-15s %-5s %-15s %-5s %5s %5s %s"
195*387f9dfdSAndroid Build Coastguard Workerlocal format_string = "%-5d %-10.10s %s%-15s %-5d %-15s %-5d %5d %5d %.2f"
196*387f9dfdSAndroid Build Coastguard Workerlocal ip_string = ""
197*387f9dfdSAndroid Build Coastguard Workerlocal ip_version = false
198*387f9dfdSAndroid Build Coastguard Workerlocal arg_timestamp = false
199*387f9dfdSAndroid Build Coastguard Workerlocal arg_csv = false
200*387f9dfdSAndroid Build Coastguard Workerlocal arg_time = false
201*387f9dfdSAndroid Build Coastguard Worker
202*387f9dfdSAndroid Build Coastguard Workerlocal examples = [[examples:
203*387f9dfdSAndroid Build Coastguard Worker    ./tcplife           # trace all TCP connect()s
204*387f9dfdSAndroid Build Coastguard Worker    ./tcplife -t        # include time column (HH:MM:SS)
205*387f9dfdSAndroid Build Coastguard Worker    ./tcplife -w        # wider columns (fit IPv6)
206*387f9dfdSAndroid Build Coastguard Worker    ./tcplife -stT      # csv output, with times & timestamps
207*387f9dfdSAndroid Build Coastguard Worker    ./tcplife -p 181    # only trace PID 181
208*387f9dfdSAndroid Build Coastguard Worker    ./tcplife -L 80     # only trace local port 80
209*387f9dfdSAndroid Build Coastguard Worker    ./tcplife -L 80,81  # only trace local ports 80 and 81
210*387f9dfdSAndroid Build Coastguard Worker    ./tcplife -D 80     # only trace remote port 80
211*387f9dfdSAndroid Build Coastguard Worker]]
212*387f9dfdSAndroid Build Coastguard Worker
213*387f9dfdSAndroid Build Coastguard Workerlocal function split(str,sep)
214*387f9dfdSAndroid Build Coastguard Worker   local t = {}
215*387f9dfdSAndroid Build Coastguard Worker   for w in string.gmatch(str, '([^,]+)') do
216*387f9dfdSAndroid Build Coastguard Worker      table.insert(t, w)
217*387f9dfdSAndroid Build Coastguard Worker   end
218*387f9dfdSAndroid Build Coastguard Worker   return t
219*387f9dfdSAndroid Build Coastguard Workerend
220*387f9dfdSAndroid Build Coastguard Worker
221*387f9dfdSAndroid Build Coastguard Workerlocal function inet_ntop(af, addr, len)
222*387f9dfdSAndroid Build Coastguard Worker   local addr_dst = ffi.new("char[?]", len)
223*387f9dfdSAndroid Build Coastguard Worker   local addr_src
224*387f9dfdSAndroid Build Coastguard Worker   if af == AF_INET then
225*387f9dfdSAndroid Build Coastguard Worker      addr_src = ffi.new("uint64_t[1]", addr)
226*387f9dfdSAndroid Build Coastguard Worker   else
227*387f9dfdSAndroid Build Coastguard Worker      addr_src = ffi.new("uint64_t[2]", addr)
228*387f9dfdSAndroid Build Coastguard Worker   end
229*387f9dfdSAndroid Build Coastguard Worker   ffi.C.inet_ntop(af, addr_src, addr_dst, len)
230*387f9dfdSAndroid Build Coastguard Worker   return ffi.string(addr_dst, len)
231*387f9dfdSAndroid Build Coastguard Workerend
232*387f9dfdSAndroid Build Coastguard Worker
233*387f9dfdSAndroid Build Coastguard Workerlocal function inet_ntohs(port)
234*387f9dfdSAndroid Build Coastguard Worker   local p = tonumber(port)
235*387f9dfdSAndroid Build Coastguard Worker   return ffi.C.ntohs(p)
236*387f9dfdSAndroid Build Coastguard Workerend
237*387f9dfdSAndroid Build Coastguard Worker
238*387f9dfdSAndroid Build Coastguard Workerlocal function print_ipv4_event(cpu, event)
239*387f9dfdSAndroid Build Coastguard Worker
240*387f9dfdSAndroid Build Coastguard Worker   local event_pid = tonumber(event.pid)
241*387f9dfdSAndroid Build Coastguard Worker   local event_task = ffi.string(event.task)
242*387f9dfdSAndroid Build Coastguard Worker   local event_ports = tonumber(event.ports)
243*387f9dfdSAndroid Build Coastguard Worker   local event_tx_b = tonumber(event.tx_b)
244*387f9dfdSAndroid Build Coastguard Worker   local event_rx_b = tonumber(event.rx_b)
245*387f9dfdSAndroid Build Coastguard Worker   local event_span_us = tonumber(event.span_us)
246*387f9dfdSAndroid Build Coastguard Worker   local event_ts_us = tonumber(event.ts_us)
247*387f9dfdSAndroid Build Coastguard Worker   local event_saddr = inet_ntop(AF_INET, tonumber(event.saddr), inet_addresslen)
248*387f9dfdSAndroid Build Coastguard Worker   local event_daddr = inet_ntop(AF_INET, tonumber(event.daddr), inet_addresslen)
249*387f9dfdSAndroid Build Coastguard Worker   if arg_time then
250*387f9dfdSAndroid Build Coastguard Worker      if arg_csv then
251*387f9dfdSAndroid Build Coastguard Worker         io.write("%s," % os.date("%H:%M:%S"))
252*387f9dfdSAndroid Build Coastguard Worker      else
253*387f9dfdSAndroid Build Coastguard Worker         io.write("%-8s " % os.date("%H:%M:%S"))
254*387f9dfdSAndroid Build Coastguard Worker      end
255*387f9dfdSAndroid Build Coastguard Worker   end
256*387f9dfdSAndroid Build Coastguard Worker   if arg_timestamp then
257*387f9dfdSAndroid Build Coastguard Worker      if start_ts == 0 then
258*387f9dfdSAndroid Build Coastguard Worker         start_ts = event_ts_us
259*387f9dfdSAndroid Build Coastguard Worker      end
260*387f9dfdSAndroid Build Coastguard Worker      local delta_s = (event_ts_us - start_ts) / 1000000
261*387f9dfdSAndroid Build Coastguard Worker      if arg.csv then
262*387f9dfdSAndroid Build Coastguard Worker         io.write("%.6f," % delta_s)
263*387f9dfdSAndroid Build Coastguard Worker      else
264*387f9dfdSAndroid Build Coastguard Worker         io.write("%-9.6f " % delta_s)
265*387f9dfdSAndroid Build Coastguard Worker      end
266*387f9dfdSAndroid Build Coastguard Worker   end
267*387f9dfdSAndroid Build Coastguard Worker   local iv = ""
268*387f9dfdSAndroid Build Coastguard Worker   if ip_version then
269*387f9dfdSAndroid Build Coastguard Worker      iv = "4"
270*387f9dfdSAndroid Build Coastguard Worker   end
271*387f9dfdSAndroid Build Coastguard Worker   print(string.format(format_string, event_pid, event_task, iv,
272*387f9dfdSAndroid Build Coastguard Worker                       event_saddr, bit.rshift(event_ports,32),
273*387f9dfdSAndroid Build Coastguard Worker                       event_daddr, bit.band(event_ports,0xffffffff),
274*387f9dfdSAndroid Build Coastguard Worker                       (event_tx_b / 1024), (event_rx_b / 1024), event_span_us/ 1000))
275*387f9dfdSAndroid Build Coastguard Workerend
276*387f9dfdSAndroid Build Coastguard Worker
277*387f9dfdSAndroid Build Coastguard Worker
278*387f9dfdSAndroid Build Coastguard Workerlocal function print_ipv6_event(cpu, event)
279*387f9dfdSAndroid Build Coastguard Worker   local event_pid = tonumber(event.pid)
280*387f9dfdSAndroid Build Coastguard Worker   local event_task = ffi.string(event.task)
281*387f9dfdSAndroid Build Coastguard Worker   local event_ports = tonumber(event.ports)
282*387f9dfdSAndroid Build Coastguard Worker   local event_tx_b = tonumber(event.tx_b)
283*387f9dfdSAndroid Build Coastguard Worker   local event_rx_b = tonumber(event.rx_b)
284*387f9dfdSAndroid Build Coastguard Worker   local event_span_us = tonumber(event.span_us)
285*387f9dfdSAndroid Build Coastguard Worker   local event_ts_us = tonumber(event.ts_us)
286*387f9dfdSAndroid Build Coastguard Worker   local event_saddr = inet_ntop(AF_INET6, {tonumber(event.saddr[0]), tonumber(event.saddr[1])}, inet6_addresslen)
287*387f9dfdSAndroid Build Coastguard Worker   local event_daddr = inet_ntop(AF_INET6, {tonumber(event.daddr[0]), tonumber(event.daddr[1])}, inet6_addresslen)
288*387f9dfdSAndroid Build Coastguard Worker   if arg_time then
289*387f9dfdSAndroid Build Coastguard Worker      if arg_csv then
290*387f9dfdSAndroid Build Coastguard Worker         io.write("%s," % os.date("%H:%M:%S"))
291*387f9dfdSAndroid Build Coastguard Worker      else
292*387f9dfdSAndroid Build Coastguard Worker         io.write("%-8s " % os.date("%H:%M:%S"))
293*387f9dfdSAndroid Build Coastguard Worker      end
294*387f9dfdSAndroid Build Coastguard Worker   end
295*387f9dfdSAndroid Build Coastguard Worker   if arg_timestamp then
296*387f9dfdSAndroid Build Coastguard Worker      if start_ts == 0 then
297*387f9dfdSAndroid Build Coastguard Worker         start_ts = event_ts_us
298*387f9dfdSAndroid Build Coastguard Worker      end
299*387f9dfdSAndroid Build Coastguard Worker      local delta_s = (event_ts_us - start_ts) / 1000000
300*387f9dfdSAndroid Build Coastguard Worker      if arg.csv then
301*387f9dfdSAndroid Build Coastguard Worker         io.write("%.6f," % delta_s)
302*387f9dfdSAndroid Build Coastguard Worker      else
303*387f9dfdSAndroid Build Coastguard Worker         io.write("%-9.6f " % delta_s)
304*387f9dfdSAndroid Build Coastguard Worker      end
305*387f9dfdSAndroid Build Coastguard Worker   end
306*387f9dfdSAndroid Build Coastguard Worker   local iv = ""
307*387f9dfdSAndroid Build Coastguard Worker   if ip_version then
308*387f9dfdSAndroid Build Coastguard Worker      iv = "6"
309*387f9dfdSAndroid Build Coastguard Worker   end
310*387f9dfdSAndroid Build Coastguard Worker   print(string.format(format_string, event_pid, event_task, iv,
311*387f9dfdSAndroid Build Coastguard Worker                       event_saddr, bit.rshift(event_ports,32),
312*387f9dfdSAndroid Build Coastguard Worker                       event_daddr, bit.band(event_ports,0xffffffff),
313*387f9dfdSAndroid Build Coastguard Worker                       (event_tx_b / 1024), (event_rx_b / 1024), event_span_us/ 1000))
314*387f9dfdSAndroid Build Coastguard Workerend
315*387f9dfdSAndroid Build Coastguard Worker
316*387f9dfdSAndroid Build Coastguard Workerlocal function parse_arg(utils)
317*387f9dfdSAndroid Build Coastguard Worker   local parser = utils.argparse("tcplife",
318*387f9dfdSAndroid Build Coastguard Worker                                 "Trace the lifespan of TCP sessions and summarize", examples)
319*387f9dfdSAndroid Build Coastguard Worker
320*387f9dfdSAndroid Build Coastguard Worker   parser:flag("-T --time", "include time column on output (HH:MM:SS)")
321*387f9dfdSAndroid Build Coastguard Worker   parser:flag("-t --timestamp", "include timestamp on output (seconds)")
322*387f9dfdSAndroid Build Coastguard Worker   parser:flag("-w --wide", "wide column output (fits IPv6 addresses)")
323*387f9dfdSAndroid Build Coastguard Worker   parser:flag("-s --csv", "comma separated values output")
324*387f9dfdSAndroid Build Coastguard Worker   parser:option("-p --pid", "trace this PID only"):convert(tonumber)
325*387f9dfdSAndroid Build Coastguard Worker   parser:option("-L --localport", "comma-separated list of local ports to trace.")
326*387f9dfdSAndroid Build Coastguard Worker   parser:option("-D --remoteport", "comma-separated list of remote ports to trace.")
327*387f9dfdSAndroid Build Coastguard Worker
328*387f9dfdSAndroid Build Coastguard Worker   local args = parser:parse()
329*387f9dfdSAndroid Build Coastguard Worker   if args.pid then
330*387f9dfdSAndroid Build Coastguard Worker      local filter = 'if (pid != %d) { return 0; }' % args.pid
331*387f9dfdSAndroid Build Coastguard Worker      program = program.gsub('FILTER_PID', filter)
332*387f9dfdSAndroid Build Coastguard Worker   end
333*387f9dfdSAndroid Build Coastguard Worker
334*387f9dfdSAndroid Build Coastguard Worker   if args.remoteport then
335*387f9dfdSAndroid Build Coastguard Worker      local dports = split(args.remoteport, ",")
336*387f9dfdSAndroid Build Coastguard Worker      local dports_if = ""
337*387f9dfdSAndroid Build Coastguard Worker      for i,d in ipairs(dports) do
338*387f9dfdSAndroid Build Coastguard Worker         if dports_if == "" then
339*387f9dfdSAndroid Build Coastguard Worker            dports_if = 'dport != %d' % inet_ntohs(d)
340*387f9dfdSAndroid Build Coastguard Worker         else
341*387f9dfdSAndroid Build Coastguard Worker            dports_if = dports_if .. ' && ' .. ('dport != %d' % inet_ntohs(d))
342*387f9dfdSAndroid Build Coastguard Worker         end
343*387f9dfdSAndroid Build Coastguard Worker      end
344*387f9dfdSAndroid Build Coastguard Worker      local filter = "if (%s) { birth.delete(&sk); return 0; }" % dports_if
345*387f9dfdSAndroid Build Coastguard Worker      program = program:gsub('FILTER_DPORT', filter)
346*387f9dfdSAndroid Build Coastguard Worker   end
347*387f9dfdSAndroid Build Coastguard Worker   if args.localport then
348*387f9dfdSAndroid Build Coastguard Worker      local lports = split(args.localport,",")
349*387f9dfdSAndroid Build Coastguard Worker      local lports_if = ""
350*387f9dfdSAndroid Build Coastguard Worker      for i,l in ipairs(lports) do
351*387f9dfdSAndroid Build Coastguard Worker         if lports_if == "" then
352*387f9dfdSAndroid Build Coastguard Worker            lports_if = 'lport != %d' % inet_ntohs(l)
353*387f9dfdSAndroid Build Coastguard Worker         else
354*387f9dfdSAndroid Build Coastguard Worker            lports_if = lports_if .. ' && ' .. ('lport != %d' % inet_ntohs(l))
355*387f9dfdSAndroid Build Coastguard Worker         end
356*387f9dfdSAndroid Build Coastguard Worker      end
357*387f9dfdSAndroid Build Coastguard Worker      local filter = "if (%s) { birth.delete(&sk); return 0; }" % lports_if
358*387f9dfdSAndroid Build Coastguard Worker      program = program:gsub('FILTER_LPORT', filter)
359*387f9dfdSAndroid Build Coastguard Worker   end
360*387f9dfdSAndroid Build Coastguard Worker   program = program:gsub('FILTER_PID', '')
361*387f9dfdSAndroid Build Coastguard Worker   program = program:gsub('FILTER_DPORT', '')
362*387f9dfdSAndroid Build Coastguard Worker   program = program:gsub('FILTER_LPORT', '')
363*387f9dfdSAndroid Build Coastguard Worker
364*387f9dfdSAndroid Build Coastguard Worker   if args.wide then
365*387f9dfdSAndroid Build Coastguard Worker      header_string = "%-5s %-16.16s %-2s %-39s %-5s %-39s %-5s %6s %6s %s"
366*387f9dfdSAndroid Build Coastguard Worker      format_string = "%-5d %-16.16s %-2s %-39s %-5s %-39s %-5d %6d %6d %.2f"
367*387f9dfdSAndroid Build Coastguard Worker      ip_string = "IP"
368*387f9dfdSAndroid Build Coastguard Worker      ip_version = true
369*387f9dfdSAndroid Build Coastguard Worker   end
370*387f9dfdSAndroid Build Coastguard Worker   if args.csv then
371*387f9dfdSAndroid Build Coastguard Worker      header_string = "%s,%s,%s,%s,%s,%s,%s,%s,%s,%s"
372*387f9dfdSAndroid Build Coastguard Worker      format_string = "%d,%s,%s,%s,%s,%s,%d,%d,%d,%.2f"
373*387f9dfdSAndroid Build Coastguard Worker      ip_string = "IP"
374*387f9dfdSAndroid Build Coastguard Worker      ip_version = true
375*387f9dfdSAndroid Build Coastguard Worker      arg_csv = true
376*387f9dfdSAndroid Build Coastguard Worker   end
377*387f9dfdSAndroid Build Coastguard Worker
378*387f9dfdSAndroid Build Coastguard Worker   if args.time then
379*387f9dfdSAndroid Build Coastguard Worker      arg_time = true
380*387f9dfdSAndroid Build Coastguard Worker      if args.csv then
381*387f9dfdSAndroid Build Coastguard Worker         io.write("%s," % ("TIME"))
382*387f9dfdSAndroid Build Coastguard Worker      else
383*387f9dfdSAndroid Build Coastguard Worker         io.write("%-8s " % ("TIME"))
384*387f9dfdSAndroid Build Coastguard Worker      end
385*387f9dfdSAndroid Build Coastguard Worker   end
386*387f9dfdSAndroid Build Coastguard Worker
387*387f9dfdSAndroid Build Coastguard Worker   if args.timestamp then
388*387f9dfdSAndroid Build Coastguard Worker      arg_timestamp = true
389*387f9dfdSAndroid Build Coastguard Worker      if args.csv then
390*387f9dfdSAndroid Build Coastguard Worker         io.write("%s," % ("TIME(s)"))
391*387f9dfdSAndroid Build Coastguard Worker      else
392*387f9dfdSAndroid Build Coastguard Worker         io.write("%-9s " % ("TIME(s)"))
393*387f9dfdSAndroid Build Coastguard Worker      end
394*387f9dfdSAndroid Build Coastguard Worker   end
395*387f9dfdSAndroid Build Coastguard Worker
396*387f9dfdSAndroid Build Coastguard Workerend
397*387f9dfdSAndroid Build Coastguard Worker
398*387f9dfdSAndroid Build Coastguard Workerreturn function(BPF, utils)
399*387f9dfdSAndroid Build Coastguard Worker   parse_arg(utils)
400*387f9dfdSAndroid Build Coastguard Worker   if debug then
401*387f9dfdSAndroid Build Coastguard Worker      print(program)
402*387f9dfdSAndroid Build Coastguard Worker   end
403*387f9dfdSAndroid Build Coastguard Worker
404*387f9dfdSAndroid Build Coastguard Worker   local bpf = BPF:new{text=program}
405*387f9dfdSAndroid Build Coastguard Worker   bpf:attach_kprobe{event="tcp_set_state", fn_name="trace_tcp_set_state"}
406*387f9dfdSAndroid Build Coastguard Worker   print(header_string % {"PID", "COMM",
407*387f9dfdSAndroid Build Coastguard Worker                          ip_string, "LADDR",
408*387f9dfdSAndroid Build Coastguard Worker                          "LPORT", "RADDR", "RPORT", "TX_KB", "RX_KB", "MS"})
409*387f9dfdSAndroid Build Coastguard Worker   local TASK_COMM_LEN = 16 -- linux/sched.h
410*387f9dfdSAndroid Build Coastguard Worker   bpf:get_table("ipv4_events"):open_perf_buffer(print_ipv4_event, [[
411*387f9dfdSAndroid Build Coastguard Worker    struct {
412*387f9dfdSAndroid Build Coastguard Worker      uint64_t ts_us;
413*387f9dfdSAndroid Build Coastguard Worker      uint64_t pid;
414*387f9dfdSAndroid Build Coastguard Worker      uint64_t saddr;
415*387f9dfdSAndroid Build Coastguard Worker      uint64_t daddr;
416*387f9dfdSAndroid Build Coastguard Worker      uint64_t ports;
417*387f9dfdSAndroid Build Coastguard Worker      uint64_t rx_b;
418*387f9dfdSAndroid Build Coastguard Worker      uint64_t tx_b;
419*387f9dfdSAndroid Build Coastguard Worker      uint64_t span_us;
420*387f9dfdSAndroid Build Coastguard Worker      char task[$];
421*387f9dfdSAndroid Build Coastguard Worker    }
422*387f9dfdSAndroid Build Coastguard Worker   ]], {TASK_COMM_LEN}, 64)
423*387f9dfdSAndroid Build Coastguard Worker   bpf:get_table("ipv6_events"):open_perf_buffer(print_ipv6_event, [[
424*387f9dfdSAndroid Build Coastguard Worker    struct {
425*387f9dfdSAndroid Build Coastguard Worker      uint64_t ts_us;
426*387f9dfdSAndroid Build Coastguard Worker      uint64_t pid;
427*387f9dfdSAndroid Build Coastguard Worker      uint64_t saddr[2];
428*387f9dfdSAndroid Build Coastguard Worker      uint64_t daddr[2];
429*387f9dfdSAndroid Build Coastguard Worker      uint64_t ports;
430*387f9dfdSAndroid Build Coastguard Worker      uint64_t rx_b;
431*387f9dfdSAndroid Build Coastguard Worker      uint64_t tx_b;
432*387f9dfdSAndroid Build Coastguard Worker      uint64_t span_us;
433*387f9dfdSAndroid Build Coastguard Worker      char task[$];
434*387f9dfdSAndroid Build Coastguard Worker    }
435*387f9dfdSAndroid Build Coastguard Worker   ]], {TASK_COMM_LEN}, 64)
436*387f9dfdSAndroid Build Coastguard Worker
437*387f9dfdSAndroid Build Coastguard Worker   bpf:perf_buffer_poll_loop()
438*387f9dfdSAndroid Build Coastguard Workerend
439