blob: 67a2894034c386d2953e65449ef7f57a17c0b0de [file] [log] [blame]
Brendan Gregg870b1cd2015-09-25 17:01:17 -07001#!/usr/bin/python
2#
3# tcpv4connect Trace TCP IPv4 connect()s.
4# For Linux, uses BCC, eBPF. Embedded C.
5#
6# USAGE: tcpv4connect [-h] [-t] [-p PID]
7#
8# Copyright (c) 2015 Brendan Gregg.
9# Licensed under the Apache License, Version 2.0 (the "License")
10#
11# 25-Sep-2015 Brendan Gregg Created this.
12
13from __future__ import print_function
14from bcc import BPF
15import argparse
16
17# arguments
18examples = """examples:
19 ./tcpv4connect # trace all open() syscalls
20 ./tcpv4connect -t # include timestamps
21 ./tcpv4connect -p 181 # only trace PID 181
22"""
23parser = argparse.ArgumentParser(
24 description="Trace TCP IPv4 connects",
25 formatter_class=argparse.RawDescriptionHelpFormatter,
26 epilog=examples)
27parser.add_argument("-t", "--timestamp", action="store_true",
28 help="include timestamp on output")
29parser.add_argument("-p", "--pid",
30 help="trace this PID only")
31args = parser.parse_args()
32debug = 0
33
34# define BPF program
35bpf_text = """
36#include <uapi/linux/ptrace.h>
37#include <net/sock.h>
38#include <bcc/proto.h>
39
40BPF_HASH(currsock, u32, struct sock *);
41
42int kprobe__tcp_v4_connect(struct pt_regs *ctx, struct sock *sk)
43{
44 u32 pid = bpf_get_current_pid_tgid();
45 FILTER
46
47 // stash the sock ptr for lookup on return
48 currsock.update(&pid, &sk);
49
50 return 0;
51};
52
53int kretprobe__tcp_v4_connect(struct pt_regs *ctx)
54{
55 int ret = ctx->ax;
56 u32 pid = bpf_get_current_pid_tgid();
57
58 struct sock **skpp;
59 skpp = currsock.lookup(&pid);
60 if (skpp == 0) {
61 return 0; // missed entry
62 }
63
Yonghong Song366eb2e2015-10-07 08:59:42 -070064 if (ret != 0) {
65 // failed to send SYNC packet, socket __sk_common.{skc_rcv_saddr, ...}
66 // may not be populated properly.
67 currsock.delete(&pid);
68 return 0;
69 }
70
Brendan Gregg870b1cd2015-09-25 17:01:17 -070071 // pull in details
72 struct sock *skp = *skpp;
73 u32 saddr = 0, daddr = 0;
74 u16 dport = 0;
75 bpf_probe_read(&saddr, sizeof(saddr), &skp->__sk_common.skc_rcv_saddr);
76 bpf_probe_read(&daddr, sizeof(daddr), &skp->__sk_common.skc_daddr);
77 bpf_probe_read(&dport, sizeof(dport), &skp->__sk_common.skc_dport);
78
79 // output
80 bpf_trace_printk("%x %x %d\\n", saddr, daddr, ntohs(dport));
81
82 currsock.delete(&pid);
83
84 return 0;
85}
86"""
87
88# code substitutions
89if args.pid:
90 bpf_text = bpf_text.replace('FILTER',
91 'if (pid != %s) { return 0; }' % args.pid)
92else:
93 bpf_text = bpf_text.replace('FILTER', '')
94if debug:
95 print(bpf_text)
96
97# initialize BPF
98b = BPF(text=bpf_text)
99
100# header
101if args.timestamp:
102 print("%-9s" % ("TIME(s)"), end="")
103print("%-6s %-12s %-16s %-16s %-4s" % ("PID", "COMM", "SADDR", "DADDR",
104 "DPORT"))
105
106start_ts = 0
107
108def inet_ntoa(addr):
109 dq = ''
110 for i in range(0, 4):
111 dq = dq + str(addr & 0xff)
112 if (i != 3):
113 dq = dq + '.'
114 addr = addr >> 8
115 return dq
116
117# format output
118while 1:
119 (task, pid, cpu, flags, ts, msg) = b.trace_fields()
120 (saddr_hs, daddr_hs, dport_s) = msg.split(" ")
121
122 if args.timestamp:
123 if start_ts == 0:
124 start_ts = ts
125 print("%-9.3f" % (ts - start_ts), end="")
126 print("%-6d %-12.12s %-16s %-16s %-4s" % (pid, task,
127 inet_ntoa(int(saddr_hs, 16)),
128 inet_ntoa(int(daddr_hs, 16)),
129 dport_s))