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";