github.com/inspektor-gadget/inspektor-gadget@v0.28.1/pkg/gadgets/profile/tcprtt/tracer/bpf/tcprtt.bpf.c (about)

     1  // SPDX-License-Identifier: GPL-2.0
     2  // Copyright (c) 2021 Wenbo Zhang
     3  // Copyright (c) 2023 The Inspektor Gadget authors
     4  #include <vmlinux.h>
     5  #include <bpf/bpf_helpers.h>
     6  #include <bpf/bpf_core_read.h>
     7  #include <bpf/bpf_tracing.h>
     8  #include <bpf/bpf_endian.h>
     9  #include "tcprtt.h"
    10  #include <gadget/bits.bpf.h>
    11  #include <gadget/maps.bpf.h>
    12  
    13  /* Taken from kernel include/linux/socket.h. */
    14  #define AF_INET 2 /* IP version 4			*/
    15  #define AF_INET6 10 /* IP version 6			*/
    16  
    17  const volatile bool targ_laddr_hist = false;
    18  const volatile bool targ_raddr_hist = false;
    19  const volatile __u16 targ_sport = 0;
    20  const volatile __u16 targ_dport = 0;
    21  const volatile __u32 targ_saddr = 0;
    22  const volatile __u32 targ_daddr = 0;
    23  const volatile __u8 targ_saddr_v6[IPV6_LEN] = {};
    24  const volatile __u8 targ_daddr_v6[IPV6_LEN] = {};
    25  const volatile bool targ_ms = false;
    26  
    27  #define MAX_ENTRIES 10240
    28  
    29  struct {
    30  	__uint(type, BPF_MAP_TYPE_HASH);
    31  	__uint(max_entries, MAX_ENTRIES);
    32  	__type(key, struct hist_key);
    33  	__type(value, struct hist);
    34  } hists SEC(".maps");
    35  
    36  static struct hist zero;
    37  
    38  /*
    39   * We cannot use the following:
    40   * __builtin_memcmp(targ_*addr_v6, *, sizeof(targ_*addr_v6));
    41   * Indeed, by using the builtin, we would discard the volatile qualifier of
    42   * targ_*addr_v6, so the compiler would optimize it and replaces the call
    43   * with 0.
    44   * So, using the volatile qualifier ensures this function is called at runtime.
    45   */
    46  static bool inline ipv6_is_not_zero(const volatile __u8 addr[IPV6_LEN])
    47  {
    48  	for (int i = 0; i < IPV6_LEN; i++)
    49  		if (addr[i])
    50  			return true;
    51  	return false;
    52  }
    53  
    54  static bool inline ipv6_are_different(const volatile __u8 a[IPV6_LEN],
    55  				      const __u8 b[IPV6_LEN])
    56  {
    57  	for (int i = 0; i < IPV6_LEN; i++)
    58  		if (a[i] != b[i])
    59  			return true;
    60  	return false;
    61  }
    62  
    63  static int handle_tcp_rcv_established(struct sock *sk)
    64  {
    65  	const struct inet_sock *inet = (struct inet_sock *)(sk);
    66  	struct tcp_sock *ts;
    67  	struct hist *histp;
    68  	struct hist_key key = {};
    69  	u64 slot;
    70  	u32 srtt;
    71  
    72  	if (targ_sport && targ_sport != BPF_CORE_READ(inet, inet_sport))
    73  		return 0;
    74  
    75  	if (targ_dport &&
    76  	    targ_dport != BPF_CORE_READ(sk, __sk_common.skc_dport))
    77  		return 0;
    78  
    79  	key.family = BPF_CORE_READ(sk, __sk_common.skc_family);
    80  	switch (key.family) {
    81  	case AF_INET:
    82  		/* If we set any of IPv6 address, we do not care about IPv4 ones. */
    83  		if (ipv6_is_not_zero(targ_saddr_v6) ||
    84  		    ipv6_is_not_zero(targ_daddr_v6))
    85  			return 0;
    86  
    87  		if (targ_saddr && targ_saddr != BPF_CORE_READ(inet, inet_saddr))
    88  			return 0;
    89  
    90  		if (targ_daddr &&
    91  		    targ_daddr != BPF_CORE_READ(sk, __sk_common.skc_daddr))
    92  			return 0;
    93  
    94  		break;
    95  	case AF_INET6:
    96  		/*
    97  		 * Reciprocal of the above: if we set any of IPv4 address, we do not care
    98  		 * about IPv6 ones.
    99  		 */
   100  		if (targ_saddr || targ_daddr)
   101  			return 0;
   102  
   103  		if (ipv6_is_not_zero(targ_saddr_v6) &&
   104  		    ipv6_are_different(targ_saddr_v6,
   105  				       BPF_CORE_READ(inet, pinet6,
   106  						     saddr.in6_u.u6_addr8)))
   107  			return 0;
   108  
   109  		if (ipv6_is_not_zero(targ_daddr_v6) &&
   110  		    ipv6_are_different(
   111  			    targ_daddr_v6,
   112  			    BPF_CORE_READ(
   113  				    sk,
   114  				    __sk_common.skc_v6_daddr.in6_u.u6_addr8)))
   115  			return 0;
   116  
   117  		break;
   118  	default:
   119  		return 0;
   120  	}
   121  
   122  	if (targ_laddr_hist) {
   123  		if (key.family == AF_INET6)
   124  			bpf_probe_read_kernel(
   125  				&key.addr, sizeof(key.addr),
   126  				BPF_CORE_READ(inet, pinet6,
   127  					      saddr.in6_u.u6_addr8));
   128  		else
   129  			/*
   130  			 * It is fine to use "->" operator with bpf_probe_read_kernel() as we are
   131  			 * using vmlinux.h which defines struct with preserve_access_index
   132  			 * attribute, see:
   133  			 * https://nakryiko.com/posts/bpf-core-reference-guide/#defining-own-co-re-relocatable-type-definitions
   134  			 */
   135  			bpf_probe_read_kernel(&key.addr,
   136  					      sizeof(inet->inet_saddr),
   137  					      &inet->inet_saddr);
   138  	} else if (targ_raddr_hist) {
   139  		if (key.family == AF_INET6)
   140  			bpf_probe_read_kernel(
   141  				&key.addr, sizeof(key.addr),
   142  				BPF_CORE_READ(sk, __sk_common.skc_v6_daddr.in6_u
   143  							  .u6_addr8));
   144  		else
   145  			bpf_probe_read_kernel(&key.addr,
   146  					      sizeof(sk->__sk_common.skc_daddr),
   147  					      &sk->__sk_common.skc_daddr);
   148  	} else {
   149  		key.family = 0;
   150  	}
   151  
   152  	histp = bpf_map_lookup_or_try_init(&hists, &key, &zero);
   153  	if (!histp)
   154  		return 0;
   155  	ts = (struct tcp_sock *)(sk);
   156  	srtt = BPF_CORE_READ(ts, srtt_us) >> 3;
   157  	if (targ_ms)
   158  		srtt /= 1000U;
   159  	slot = log2l(srtt);
   160  	if (slot >= MAX_SLOTS)
   161  		slot = MAX_SLOTS - 1;
   162  	__sync_fetch_and_add(&histp->slots[slot], 1);
   163  	__sync_fetch_and_add(&histp->latency, srtt);
   164  	__sync_fetch_and_add(&histp->cnt, 1);
   165  	return 0;
   166  }
   167  
   168  SEC("kprobe/tcp_rcv_established")
   169  int BPF_KPROBE(ig_tcprcvest_kp, struct sock *sk)
   170  {
   171  	return handle_tcp_rcv_established(sk);
   172  }
   173  
   174  // Enable once https://github.com/inspektor-gadget/inspektor-gadget/issues/1566 is fixed.
   175  // SEC("fentry/tcp_rcv_established")
   176  // int BPF_PROG(ig_tcprcvest_fe, struct sock *sk)
   177  // {
   178  // 	return handle_tcp_rcv_established(sk);
   179  // }
   180  
   181  char LICENSE[] SEC("license") = "Dual BSD/GPL";