2020-06-24 02:08:20 +03:00
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2020 Facebook */
# include "bpf_iter.h"
# include "bpf_tracing_net.h"
# include <bpf/bpf_helpers.h>
# include <bpf/bpf_endian.h>
char _license [ ] SEC ( " license " ) = " GPL " ;
static int hlist_unhashed_lockless ( const struct hlist_node * h )
{
return ! ( h - > pprev ) ;
}
static int timer_pending ( const struct timer_list * timer )
{
return ! hlist_unhashed_lockless ( & timer - > entry ) ;
}
extern unsigned CONFIG_HZ __kconfig ;
# define USER_HZ 100
# define NSEC_PER_SEC 1000000000ULL
static clock_t jiffies_to_clock_t ( unsigned long x )
{
/* The implementation here tailored to a particular
* setting of USER_HZ .
*/
u64 tick_nsec = ( NSEC_PER_SEC + CONFIG_HZ / 2 ) / CONFIG_HZ ;
u64 user_hz_nsec = NSEC_PER_SEC / USER_HZ ;
if ( ( tick_nsec % user_hz_nsec ) = = 0 ) {
if ( CONFIG_HZ < USER_HZ )
return x * ( USER_HZ / CONFIG_HZ ) ;
else
return x / ( CONFIG_HZ / USER_HZ ) ;
}
return x * tick_nsec / user_hz_nsec ;
}
static clock_t jiffies_delta_to_clock_t ( long delta )
{
if ( delta < = 0 )
return 0 ;
return jiffies_to_clock_t ( delta ) ;
}
static long sock_i_ino ( const struct sock * sk )
{
const struct socket * sk_socket = sk - > sk_socket ;
const struct inode * inode ;
unsigned long ino ;
if ( ! sk_socket )
return 0 ;
inode = & container_of ( sk_socket , struct socket_alloc , socket ) - > vfs_inode ;
2020-07-20 14:48:06 +03:00
bpf_probe_read_kernel ( & ino , sizeof ( ino ) , & inode - > i_ino ) ;
2020-06-24 02:08:20 +03:00
return ino ;
}
static bool
inet_csk_in_pingpong_mode ( const struct inet_connection_sock * icsk )
{
return icsk - > icsk_ack . pingpong > = TCP_PINGPONG_THRESH ;
}
static bool tcp_in_initial_slowstart ( const struct tcp_sock * tcp )
{
return tcp - > snd_ssthresh > = TCP_INFINITE_SSTHRESH ;
}
static int dump_tcp6_sock ( struct seq_file * seq , struct tcp6_sock * tp ,
uid_t uid , __u32 seq_num )
{
const struct inet_connection_sock * icsk ;
const struct fastopen_queue * fastopenq ;
const struct in6_addr * dest , * src ;
const struct inet_sock * inet ;
unsigned long timer_expires ;
const struct sock * sp ;
__u16 destp , srcp ;
int timer_active ;
int rx_queue ;
int state ;
icsk = & tp - > tcp . inet_conn ;
inet = & icsk - > icsk_inet ;
sp = & inet - > sk ;
fastopenq = & icsk - > icsk_accept_queue . fastopenq ;
dest = & sp - > sk_v6_daddr ;
src = & sp - > sk_v6_rcv_saddr ;
destp = bpf_ntohs ( inet - > inet_dport ) ;
srcp = bpf_ntohs ( inet - > inet_sport ) ;
if ( icsk - > icsk_pending = = ICSK_TIME_RETRANS | |
icsk - > icsk_pending = = ICSK_TIME_REO_TIMEOUT | |
icsk - > icsk_pending = = ICSK_TIME_LOSS_PROBE ) {
timer_active = 1 ;
timer_expires = icsk - > icsk_timeout ;
} else if ( icsk - > icsk_pending = = ICSK_TIME_PROBE0 ) {
timer_active = 4 ;
timer_expires = icsk - > icsk_timeout ;
} else if ( timer_pending ( & sp - > sk_timer ) ) {
timer_active = 2 ;
timer_expires = sp - > sk_timer . expires ;
} else {
timer_active = 0 ;
timer_expires = bpf_jiffies64 ( ) ;
}
state = sp - > sk_state ;
if ( state = = TCP_LISTEN ) {
rx_queue = sp - > sk_ack_backlog ;
} else {
rx_queue = tp - > tcp . rcv_nxt - tp - > tcp . copied_seq ;
if ( rx_queue < 0 )
rx_queue = 0 ;
}
BPF_SEQ_PRINTF ( seq , " %4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X " ,
seq_num ,
src - > s6_addr32 [ 0 ] , src - > s6_addr32 [ 1 ] ,
src - > s6_addr32 [ 2 ] , src - > s6_addr32 [ 3 ] , srcp ,
dest - > s6_addr32 [ 0 ] , dest - > s6_addr32 [ 1 ] ,
dest - > s6_addr32 [ 2 ] , dest - > s6_addr32 [ 3 ] , destp ) ;
BPF_SEQ_PRINTF ( seq , " %02X %08X:%08X %02X:%08lX %08X %5u %8d %lu %d " ,
state ,
tp - > tcp . write_seq - tp - > tcp . snd_una , rx_queue ,
timer_active ,
jiffies_delta_to_clock_t ( timer_expires - bpf_jiffies64 ( ) ) ,
icsk - > icsk_retransmits , uid ,
icsk - > icsk_probes_out ,
sock_i_ino ( sp ) ,
sp - > sk_refcnt . refs . counter ) ;
BPF_SEQ_PRINTF ( seq , " %pK %lu %lu %u %u %d \n " ,
tp ,
jiffies_to_clock_t ( icsk - > icsk_rto ) ,
jiffies_to_clock_t ( icsk - > icsk_ack . ato ) ,
( icsk - > icsk_ack . quick < < 1 ) | inet_csk_in_pingpong_mode ( icsk ) ,
tp - > tcp . snd_cwnd ,
state = = TCP_LISTEN ? fastopenq - > max_qlen
: ( tcp_in_initial_slowstart ( & tp - > tcp ) ? - 1
: tp - > tcp . snd_ssthresh )
) ;
return 0 ;
}
static int dump_tw_sock ( struct seq_file * seq , struct tcp_timewait_sock * ttw ,
uid_t uid , __u32 seq_num )
{
struct inet_timewait_sock * tw = & ttw - > tw_sk ;
const struct in6_addr * dest , * src ;
__u16 destp , srcp ;
long delta ;
delta = tw - > tw_timer . expires - bpf_jiffies64 ( ) ;
dest = & tw - > tw_v6_daddr ;
src = & tw - > tw_v6_rcv_saddr ;
destp = bpf_ntohs ( tw - > tw_dport ) ;
srcp = bpf_ntohs ( tw - > tw_sport ) ;
BPF_SEQ_PRINTF ( seq , " %4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X " ,
seq_num ,
src - > s6_addr32 [ 0 ] , src - > s6_addr32 [ 1 ] ,
src - > s6_addr32 [ 2 ] , src - > s6_addr32 [ 3 ] , srcp ,
dest - > s6_addr32 [ 0 ] , dest - > s6_addr32 [ 1 ] ,
dest - > s6_addr32 [ 2 ] , dest - > s6_addr32 [ 3 ] , destp ) ;
BPF_SEQ_PRINTF ( seq , " %02X %08X:%08X %02X:%08lX %08X %5d %8d %d %d %pK \n " ,
tw - > tw_substate , 0 , 0 ,
3 , jiffies_delta_to_clock_t ( delta ) , 0 , 0 , 0 , 0 ,
tw - > tw_refcnt . refs . counter , tw ) ;
return 0 ;
}
static int dump_req_sock ( struct seq_file * seq , struct tcp_request_sock * treq ,
uid_t uid , __u32 seq_num )
{
struct inet_request_sock * irsk = & treq - > req ;
struct request_sock * req = & irsk - > req ;
struct in6_addr * src , * dest ;
long ttd ;
ttd = req - > rsk_timer . expires - bpf_jiffies64 ( ) ;
src = & irsk - > ir_v6_loc_addr ;
dest = & irsk - > ir_v6_rmt_addr ;
if ( ttd < 0 )
ttd = 0 ;
BPF_SEQ_PRINTF ( seq , " %4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X " ,
seq_num ,
src - > s6_addr32 [ 0 ] , src - > s6_addr32 [ 1 ] ,
src - > s6_addr32 [ 2 ] , src - > s6_addr32 [ 3 ] ,
irsk - > ir_num ,
dest - > s6_addr32 [ 0 ] , dest - > s6_addr32 [ 1 ] ,
dest - > s6_addr32 [ 2 ] , dest - > s6_addr32 [ 3 ] ,
bpf_ntohs ( irsk - > ir_rmt_port ) ) ;
BPF_SEQ_PRINTF ( seq , " %02X %08X:%08X %02X:%08lX %08X %5d %8d %d %d %pK \n " ,
TCP_SYN_RECV , 0 , 0 , 1 , jiffies_to_clock_t ( ttd ) ,
req - > num_timeout , uid , 0 , 0 , 0 , req ) ;
return 0 ;
}
SEC ( " iter/tcp " )
int dump_tcp6 ( struct bpf_iter__tcp * ctx )
{
struct sock_common * sk_common = ctx - > sk_common ;
struct seq_file * seq = ctx - > meta - > seq ;
struct tcp_timewait_sock * tw ;
struct tcp_request_sock * req ;
struct tcp6_sock * tp ;
uid_t uid = ctx - > uid ;
__u32 seq_num ;
if ( sk_common = = ( void * ) 0 )
return 0 ;
seq_num = ctx - > meta - > seq_num ;
if ( seq_num = = 0 )
BPF_SEQ_PRINTF ( seq , " sl "
" local_address "
" remote_address "
" st tx_queue rx_queue tr tm->when retrnsmt "
" uid timeout inode \n " ) ;
if ( sk_common - > skc_family ! = AF_INET6 )
return 0 ;
tp = bpf_skc_to_tcp6_sock ( sk_common ) ;
if ( tp )
return dump_tcp6_sock ( seq , tp , uid , seq_num ) ;
tw = bpf_skc_to_tcp_timewait_sock ( sk_common ) ;
if ( tw )
return dump_tw_sock ( seq , tw , uid , seq_num ) ;
req = bpf_skc_to_tcp_request_sock ( sk_common ) ;
if ( req )
return dump_req_sock ( seq , req , uid , seq_num ) ;
return 0 ;
}