github.com/cilium/ebpf@v0.15.1-0.20240517100537-8079b37aa138/examples/tcprtt/tcprtt.c (about) 1 //go:build ignore 2 3 #include "common.h" 4 5 #include "bpf_endian.h" 6 #include "bpf_tracing.h" 7 8 #define AF_INET 2 9 10 char __license[] SEC("license") = "Dual MIT/GPL"; 11 12 /** 13 * For CO-RE relocatable eBPF programs, __attribute__((preserve_access_index)) 14 * preserves the offset of the specified fields in the original kernel struct. 15 * So here we don't need to include "vmlinux.h". Instead we only need to define 16 * the kernel struct and their fields the eBPF program actually requires. 17 * 18 * Also note that BTF-enabled programs like fentry, fexit, fmod_ret, tp_btf, 19 * lsm, etc. declared using the BPF_PROG macro can read kernel memory without 20 * needing to call bpf_probe_read*(). 21 */ 22 23 /** 24 * struct sock_common is the minimal network layer representation of sockets. 25 * This is a simplified copy of the kernel's struct sock_common. 26 * This copy contains only the fields needed for this example to 27 * fetch the source and destination port numbers and IP addresses. 28 */ 29 struct sock_common { 30 union { 31 struct { 32 // skc_daddr is destination IP address 33 __be32 skc_daddr; 34 // skc_rcv_saddr is the source IP address 35 __be32 skc_rcv_saddr; 36 }; 37 }; 38 union { 39 struct { 40 // skc_dport is the destination TCP/UDP port 41 __be16 skc_dport; 42 // skc_num is the source TCP/UDP port 43 __u16 skc_num; 44 }; 45 }; 46 // skc_family is the network address family (2 for IPV4) 47 short unsigned int skc_family; 48 } __attribute__((preserve_access_index)); 49 50 /** 51 * struct sock is the network layer representation of sockets. 52 * This is a simplified copy of the kernel's struct sock. 53 * This copy is needed only to access struct sock_common. 54 */ 55 struct sock { 56 struct sock_common __sk_common; 57 } __attribute__((preserve_access_index)); 58 59 /** 60 * struct tcp_sock is the Linux representation of a TCP socket. 61 * This is a simplified copy of the kernel's struct tcp_sock. 62 * For this example we only need srtt_us to read the smoothed RTT. 63 */ 64 struct tcp_sock { 65 u32 srtt_us; 66 } __attribute__((preserve_access_index)); 67 68 struct { 69 __uint(type, BPF_MAP_TYPE_RINGBUF); 70 __uint(max_entries, 1 << 24); 71 } events SEC(".maps"); 72 73 /** 74 * The sample submitted to userspace over a ring buffer. 75 * Emit struct event's type info into the ELF's BTF so bpf2go 76 * can generate a Go type from it. 77 */ 78 struct event { 79 u16 sport; 80 u16 dport; 81 u32 saddr; 82 u32 daddr; 83 u32 srtt; 84 }; 85 struct event *unused_event __attribute__((unused)); 86 87 SEC("fentry/tcp_close") 88 int BPF_PROG(tcp_close, struct sock *sk) { 89 if (sk->__sk_common.skc_family != AF_INET) { 90 return 0; 91 } 92 93 // The input struct sock is actually a tcp_sock, so we can type-cast 94 struct tcp_sock *ts = bpf_skc_to_tcp_sock(sk); 95 if (!ts) { 96 return 0; 97 } 98 99 struct event *tcp_info; 100 tcp_info = bpf_ringbuf_reserve(&events, sizeof(struct event), 0); 101 if (!tcp_info) { 102 return 0; 103 } 104 105 tcp_info->saddr = sk->__sk_common.skc_rcv_saddr; 106 tcp_info->daddr = sk->__sk_common.skc_daddr; 107 tcp_info->dport = bpf_ntohs(sk->__sk_common.skc_dport); 108 tcp_info->sport = sk->__sk_common.skc_num; 109 110 tcp_info->srtt = ts->srtt_us >> 3; 111 tcp_info->srtt /= 1000; 112 113 bpf_ringbuf_submit(tcp_info, 0); 114 115 return 0; 116 }