forked from bpftrace/bpftrace
-
Notifications
You must be signed in to change notification settings - Fork 0
/
tcpdrop.bt
executable file
·85 lines (76 loc) · 2.45 KB
/
tcpdrop.bt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
#!/usr/bin/env bpftrace
/*
* tcpdrop.bt Trace TCP kernel-dropped packets/segments.
* For Linux, uses bpftrace and eBPF.
*
* USAGE: tcpdrop.bt
*
* This is a bpftrace version of the bcc tool of the same name.
* It is limited to ipv4 addresses, and cannot show tcp flags.
*
* This provides information such as packet details, socket state, and kernel
* stack trace for packets/segments that were dropped via kfree_skb.
*
* For Linux 5.17+ (see tools/old for script for lower versions).
*
* Copyright (c) 2018 Dale Hamel.
* Licensed under the Apache License, Version 2.0 (the "License")
*
* 23-Nov-2018 Dale Hamel created this.
* 01-Oct-2022 Rong Tao use tracepoint:skb:kfree_skb
*/
#ifndef BPFTRACE_HAVE_BTF
#include <linux/socket.h>
#include <net/sock.h>
#else
#include <sys/socket.h>
#endif
BEGIN
{
printf("Tracing tcp drops. Hit Ctrl-C to end.\n");
printf("%-8s %-8s %-16s %-21s %-21s %-8s\n", "TIME", "PID", "COMM", "SADDR:SPORT", "DADDR:DPORT", "STATE");
// See https://github.com/torvalds/linux/blob/master/include/net/tcp_states.h
@tcp_states[1] = "ESTABLISHED";
@tcp_states[2] = "SYN_SENT";
@tcp_states[3] = "SYN_RECV";
@tcp_states[4] = "FIN_WAIT1";
@tcp_states[5] = "FIN_WAIT2";
@tcp_states[6] = "TIME_WAIT";
@tcp_states[7] = "CLOSE";
@tcp_states[8] = "CLOSE_WAIT";
@tcp_states[9] = "LAST_ACK";
@tcp_states[10] = "LISTEN";
@tcp_states[11] = "CLOSING";
@tcp_states[12] = "NEW_SYN_RECV";
}
tracepoint:skb:kfree_skb
{
$reason = args->reason;
$skb = (struct sk_buff *)args->skbaddr;
$sk = ((struct sock *) $skb->sk);
$inet_family = $sk->__sk_common.skc_family;
if ($reason > SKB_DROP_REASON_NOT_SPECIFIED &&
($inet_family == AF_INET || $inet_family == AF_INET6)) {
if ($inet_family == AF_INET) {
$daddr = ntop($sk->__sk_common.skc_daddr);
$saddr = ntop($sk->__sk_common.skc_rcv_saddr);
} else {
$daddr = ntop($sk->__sk_common.skc_v6_daddr.in6_u.u6_addr8);
$saddr = ntop($sk->__sk_common.skc_v6_rcv_saddr.in6_u.u6_addr8);
}
$lport = $sk->__sk_common.skc_num;
$dport = $sk->__sk_common.skc_dport;
// Destination port is big endian, it must be flipped
$dport = bswap($dport);
$state = $sk->__sk_common.skc_state;
$statestr = @tcp_states[$state];
time("%H:%M:%S ");
printf("%-8d %-16s ", pid, comm);
printf("%39s:%-6d %39s:%-6d %-10s\n", $saddr, $lport, $daddr, $dport, $statestr);
printf("%s\n", kstack);
}
}
END
{
clear(@tcp_states);
}