github.com/inspektor-gadget/inspektor-gadget@v0.28.1/pkg/gadgets/trace/tcpretrans/tracer/bpf/tcpretrans.bpf.c (about) 1 // SPDX-License-Identifier: GPL-2.0 2 // 3 // Based on tcpretrans(8) from BCC 4 // 5 // Copyright 2016 Netflix, Inc. 6 // 7 // 14-Feb-2016 Brendan Gregg Created this. 8 // 03-Nov-2017 Matthias Tafelmeier Extended this. 9 // Copyright 2023 Microsoft Corporation 10 11 #include <vmlinux.h> 12 13 #include <bpf/bpf_helpers.h> 14 #include <bpf/bpf_core_read.h> 15 #include <bpf/bpf_tracing.h> 16 #include <bpf/bpf_endian.h> 17 18 #define GADGET_TYPE_TRACING 19 #include <gadget/sockets-map.h> 20 21 #include "tcpretrans.h" 22 23 /* Define here, because there are conflicts with include files */ 24 #define AF_INET 2 25 #define AF_INET6 10 26 27 // we need this to make sure the compiler doesn't remove our struct 28 const struct event *unusedevent __attribute__((unused)); 29 30 struct { 31 __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY); 32 __uint(key_size, sizeof(__u32)); 33 __uint(value_size, sizeof(__u32)); 34 } events SEC(".maps"); 35 36 static __always_inline int __trace_tcp_retrans(void *ctx, const struct sock *sk, 37 const struct sk_buff *skb, 38 enum type type) 39 { 40 struct inet_sock *sockp; 41 struct task_struct *task; 42 __u64 pid_tgid, uid_gid; 43 struct event event = {}; 44 struct tcp_skb_cb *tcb; 45 46 if (sk == NULL) 47 return 0; 48 49 if (BPF_CORE_READ_BITFIELD_PROBED(sk, sk_protocol) != IPPROTO_TCP) 50 return 0; 51 52 sockp = (struct inet_sock *)sk; 53 task = (struct task_struct *)bpf_get_current_task(); 54 pid_tgid = bpf_get_current_pid_tgid(); 55 uid_gid = bpf_get_current_uid_gid(); 56 57 event.type = type; 58 event.timestamp = bpf_ktime_get_boot_ns(); 59 event.af = BPF_CORE_READ(sk, __sk_common.skc_family); 60 event.state = BPF_CORE_READ(sk, __sk_common.skc_state); 61 62 bpf_get_current_comm(&event.proc_current.task, 63 sizeof(event.proc_current.task)); 64 event.proc_current.pid = pid_tgid >> 32; 65 event.proc_current.tid = (__u32)pid_tgid; 66 event.proc_current.mount_ns_id = 67 (u64)BPF_CORE_READ(task, nsproxy, mnt_ns, ns.inum); 68 event.proc_current.uid = (u32)uid_gid; 69 event.proc_current.gid = (u32)(uid_gid >> 32); 70 71 // The tcp_retransmit_skb tracepoint is fired with a skb that does not 72 // contain the TCP header because the TCP header is built on a cloned skb 73 // we don't have access to. 74 // skb->transport_header is not set: skb_transport_header_was_set() == false. 75 // Instead, we have to read the TCP flags from the TCP control buffer. 76 if (skb) { 77 tcb = (struct tcp_skb_cb *)&(skb->cb[0]); 78 bpf_probe_read_kernel(&event.tcpflags, sizeof(event.tcpflags), 79 &tcb->tcp_flags); 80 } 81 82 BPF_CORE_READ_INTO(&event.dport, sk, __sk_common.skc_dport); 83 if (event.dport == 0) 84 return 0; 85 86 BPF_CORE_READ_INTO(&event.sport, sockp, inet_sport); 87 if (event.sport == 0) 88 return 0; 89 90 switch (event.af) { 91 case AF_INET: 92 BPF_CORE_READ_INTO(&event.daddr_v4, sk, __sk_common.skc_daddr); 93 if (event.daddr_v4 == 0) 94 return 0; 95 BPF_CORE_READ_INTO(&event.saddr_v4, sk, 96 __sk_common.skc_rcv_saddr); 97 if (event.saddr_v4 == 0) 98 return 0; 99 break; 100 101 case AF_INET6: 102 BPF_CORE_READ_INTO( 103 &event.saddr_v6, sk, 104 __sk_common.skc_v6_rcv_saddr.in6_u.u6_addr32); 105 if (event.saddr_v6 == 0) 106 return 0; 107 BPF_CORE_READ_INTO(&event.daddr_v6, sk, 108 __sk_common.skc_v6_daddr.in6_u.u6_addr32); 109 if (event.daddr_v6 == 0) 110 return 0; 111 break; 112 113 default: 114 // drop 115 return 0; 116 } 117 118 BPF_CORE_READ_INTO(&event.netns, sk, __sk_common.skc_net.net, ns.inum); 119 120 struct sockets_value *skb_val = gadget_socket_lookup(sk, event.netns); 121 122 if (skb_val != NULL) { 123 event.proc_socket.mount_ns_id = skb_val->mntns; 124 event.proc_socket.pid = skb_val->pid_tgid >> 32; 125 event.proc_socket.tid = (__u32)skb_val->pid_tgid; 126 __builtin_memcpy(&event.proc_socket.task, skb_val->task, 127 sizeof(event.proc_socket.task)); 128 event.proc_socket.uid = (__u32)skb_val->uid_gid; 129 event.proc_socket.gid = (__u32)(skb_val->uid_gid >> 32); 130 } 131 132 bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU, &event, 133 sizeof(event)); 134 return 0; 135 } 136 137 SEC("tracepoint/tcp/tcp_retransmit_skb") 138 int ig_tcpretrans(struct trace_event_raw_tcp_event_sk_skb *ctx) 139 { 140 // struct trace_event_raw_tcp_event_sk_skb is described in: 141 // /sys/kernel/tracing/events/tcp/tcp_retransmit_skb/format 142 const struct sk_buff *skb = ctx->skbaddr; 143 const struct sock *sk = ctx->skaddr; 144 145 return __trace_tcp_retrans(ctx, sk, skb, RETRANS); 146 } 147 148 SEC("kprobe/tcp_send_loss_probe") 149 int BPF_KPROBE(ig_tcplossprobe, struct sock *sk) 150 { 151 return __trace_tcp_retrans(ctx, sk, NULL, LOSS); 152 } 153 154 char LICENSE[] SEC("license") = "GPL";