55#include <bpf/bpf_core_read.h>
66#include <bpf/bpf_tracing.h>
77
8+ #include "bits.bpf.h"
89#include "compat.bpf.h"
910#include "core_fixes.bpf.h"
11+ #include "maps.bpf.h"
1012#include "tcppktlat.h"
1113
12- #define MAX_ENTRIES 10240
13- #define AF_INET 2
14+ #define MAX_ENTRIES 10240
15+ #define AF_INET 2
1416
1517const volatile pid_t targ_pid = 0 ;
1618const volatile pid_t targ_tid = 0 ;
1719const volatile __u16 targ_sport = 0 ;
1820const volatile __u16 targ_dport = 0 ;
1921const volatile __u64 targ_min_us = 0 ;
22+ const volatile bool targ_hist = false;
23+ const volatile bool targ_per_thread = false;
2024
2125struct {
2226 __uint (type , BPF_MAP_TYPE_HASH );
@@ -25,6 +29,15 @@ struct {
2529 __type (value , u64 );
2630} start SEC (".maps" );
2731
32+ static struct hist zero ;
33+
34+ struct {
35+ __uint (type , BPF_MAP_TYPE_HASH );
36+ __uint (max_entries , MAX_ENTRIES );
37+ __type (key , u32 );
38+ __type (value , struct hist );
39+ } hists SEC (".maps" );
40+
2841static int handle_tcp_probe (struct sock * sk , struct sk_buff * skb )
2942{
3043 const struct inet_sock * inet = (struct inet_sock * )(sk );
@@ -33,9 +46,10 @@ static int handle_tcp_probe(struct sock *sk, struct sk_buff *skb)
3346
3447 if (targ_sport && targ_sport != BPF_CORE_READ (inet , inet_sport ))
3548 return 0 ;
36- if (targ_dport && targ_dport != BPF_CORE_READ (sk , __sk_common .skc_dport ))
49+ if (targ_dport &&
50+ targ_dport != BPF_CORE_READ (sk , __sk_common .skc_dport ))
3751 return 0 ;
38- th = (const struct tcphdr * )BPF_CORE_READ (skb , data );
52+ th = (const struct tcphdr * )BPF_CORE_READ (skb , data );
3953 doff = BPF_CORE_READ_BITFIELD_PROBED (th , doff );
4054 len = BPF_CORE_READ (skb , len );
4155 /* `doff * 4` means `__tcp_hdrlen` */
@@ -70,26 +84,70 @@ static int handle_tcp_rcv_space_adjust(void *ctx, struct sock *sk)
7084 if (delta_us < 0 || delta_us <= targ_min_us )
7185 goto cleanup ;
7286
73- eventp = reserve_buf (sizeof (* eventp ));
74- if (!eventp )
75- goto cleanup ;
76-
77- eventp -> pid = pid ;
78- eventp -> tid = tid ;
79- eventp -> delta_us = delta_us ;
80- eventp -> sport = BPF_CORE_READ (inet , inet_sport );
81- eventp -> dport = BPF_CORE_READ (sk , __sk_common .skc_dport );
82- bpf_get_current_comm (& eventp -> comm , TASK_COMM_LEN );
83- family = BPF_CORE_READ (sk , __sk_common .skc_family );
84- if (family == AF_INET ) {
85- eventp -> saddr [0 ] = BPF_CORE_READ (sk , __sk_common .skc_rcv_saddr );
86- eventp -> daddr [0 ] = BPF_CORE_READ (sk , __sk_common .skc_daddr );
87- } else { /* family == AF_INET6 */
88- BPF_CORE_READ_INTO (eventp -> saddr , sk , __sk_common .skc_v6_rcv_saddr .in6_u .u6_addr32 );
89- BPF_CORE_READ_INTO (eventp -> daddr , sk , __sk_common .skc_v6_daddr .in6_u .u6_addr32 );
87+ if (targ_hist ) {
88+ struct hist * histp ;
89+ struct task_struct * current ;
90+ u32 hkey ;
91+ u64 slot ;
92+
93+ /* Use TID for per-thread, PID (tgid) for per-process */
94+ if (targ_per_thread )
95+ hkey = tid ;
96+ else
97+ hkey = pid ;
98+
99+ histp = bpf_map_lookup_or_try_init (& hists , & hkey , & zero );
100+ if (!histp )
101+ goto cleanup ;
102+
103+ /* Store comm if not already set */
104+ if (!histp -> comm [0 ]) {
105+ if (targ_per_thread ) {
106+ /* For per-thread, use current thread comm */
107+ bpf_get_current_comm (& histp -> comm ,
108+ TASK_COMM_LEN );
109+ } else {
110+ /* For per-process, use process group leader comm */
111+ current = (struct task_struct * )
112+ bpf_get_current_task ();
113+ BPF_CORE_READ_STR_INTO (& histp -> comm ,
114+ current ,
115+ group_leader ,
116+ comm );
117+ }
118+ }
119+ slot = log2l (delta_us );
120+ if (slot >= MAX_SLOTS )
121+ slot = MAX_SLOTS - 1 ;
122+ __sync_fetch_and_add (& histp -> slots [slot ], 1 );
123+ } else {
124+ eventp = reserve_buf (sizeof (* eventp ));
125+ if (!eventp )
126+ goto cleanup ;
127+
128+ eventp -> pid = pid ;
129+ eventp -> tid = tid ;
130+ eventp -> delta_us = delta_us ;
131+ eventp -> sport = BPF_CORE_READ (inet , inet_sport );
132+ eventp -> dport = BPF_CORE_READ (sk , __sk_common .skc_dport );
133+ bpf_get_current_comm (& eventp -> comm , TASK_COMM_LEN );
134+ family = BPF_CORE_READ (sk , __sk_common .skc_family );
135+ if (family == AF_INET ) {
136+ eventp -> saddr [0 ] =
137+ BPF_CORE_READ (sk , __sk_common .skc_rcv_saddr );
138+ eventp -> daddr [0 ] =
139+ BPF_CORE_READ (sk , __sk_common .skc_daddr );
140+ } else { /* family == AF_INET6 */
141+ BPF_CORE_READ_INTO (
142+ eventp -> saddr , sk ,
143+ __sk_common .skc_v6_rcv_saddr .in6_u .u6_addr32 );
144+ BPF_CORE_READ_INTO (
145+ eventp -> daddr , sk ,
146+ __sk_common .skc_v6_daddr .in6_u .u6_addr32 );
147+ }
148+ eventp -> family = family ;
149+ submit_buf (ctx , eventp , sizeof (* eventp ));
90150 }
91- eventp -> family = family ;
92- submit_buf (ctx , eventp , sizeof (* eventp ));
93151
94152cleanup :
95153 bpf_map_delete_elem (& start , & sock_ident );
@@ -123,7 +181,8 @@ int BPF_PROG(tcp_destroy_sock_btf, struct sock *sk)
123181}
124182
125183SEC ("raw_tp/tcp_probe" )
126- int BPF_PROG (tcp_probe , struct sock * sk , struct sk_buff * skb ) {
184+ int BPF_PROG (tcp_probe , struct sock * sk , struct sk_buff * skb )
185+ {
127186 return handle_tcp_probe (sk , skb );
128187}
129188
0 commit comments