github.com/inspektor-gadget/inspektor-gadget@v0.28.1/pkg/gadgets/top/tcp/tracer/bpf/tcptop.bpf.c (about)

     1  // SPDX-License-Identifier: GPL-2.0
     2  // Copyright (c) 2022 Francis Laniel <flaniel@linux.microsoft.com>
     3  #include <vmlinux.h>
     4  #include <bpf/bpf_helpers.h>
     5  #include <bpf/bpf_core_read.h>
     6  #include <bpf/bpf_tracing.h>
     7  #include <bpf/bpf_endian.h>
     8  
     9  #include "tcptop.h"
    10  #include <gadget/mntns_filter.h>
    11  
    12  /* Taken from kernel include/linux/socket.h. */
    13  #define AF_INET 2 /* Internet IP Protocol 	*/
    14  #define AF_INET6 10 /* IP version 6			*/
    15  
    16  const volatile pid_t target_pid = 0;
    17  const volatile int target_family = -1;
    18  
    19  struct {
    20  	__uint(type, BPF_MAP_TYPE_HASH);
    21  	__uint(max_entries, 10240);
    22  	__type(key, struct ip_key_t);
    23  	__type(value, struct traffic_t);
    24  } ip_map SEC(".maps");
    25  
    26  static int probe_ip(bool receiving, struct sock *sk, size_t size)
    27  {
    28  	struct ip_key_t ip_key = {};
    29  	struct traffic_t *trafficp;
    30  	u64 mntns_id;
    31  	u16 family;
    32  	u32 pid;
    33  
    34  	pid = bpf_get_current_pid_tgid() >> 32;
    35  	if (target_pid != 0 && target_pid != pid)
    36  		return 0;
    37  
    38  	family = BPF_CORE_READ(sk, __sk_common.skc_family);
    39  	if (target_family != -1 && target_family != family)
    40  		return 0;
    41  
    42  	/* drop */
    43  	if (family != AF_INET && family != AF_INET6)
    44  		return 0;
    45  
    46  	mntns_id = gadget_get_mntns_id();
    47  
    48  	if (gadget_should_discard_mntns_id(mntns_id))
    49  		return 0;
    50  
    51  	ip_key.pid = pid;
    52  	bpf_get_current_comm(&ip_key.name, sizeof(ip_key.name));
    53  	ip_key.lport = BPF_CORE_READ(sk, __sk_common.skc_num);
    54  	ip_key.dport = bpf_ntohs(BPF_CORE_READ(sk, __sk_common.skc_dport));
    55  	ip_key.family = family;
    56  	ip_key.mntnsid = mntns_id;
    57  
    58  	if (family == AF_INET) {
    59  		bpf_probe_read_kernel(&ip_key.saddr,
    60  				      sizeof(sk->__sk_common.skc_rcv_saddr),
    61  				      &sk->__sk_common.skc_rcv_saddr);
    62  		bpf_probe_read_kernel(&ip_key.daddr,
    63  				      sizeof(sk->__sk_common.skc_daddr),
    64  				      &sk->__sk_common.skc_daddr);
    65  	} else {
    66  		/*
    67  		 * family == AF_INET6,
    68  		 * we already checked above family is correct.
    69  		 */
    70  		bpf_probe_read_kernel(
    71  			&ip_key.saddr,
    72  			sizeof(sk->__sk_common.skc_v6_rcv_saddr.in6_u.u6_addr32),
    73  			&sk->__sk_common.skc_v6_rcv_saddr.in6_u.u6_addr32);
    74  		bpf_probe_read_kernel(
    75  			&ip_key.daddr,
    76  			sizeof(sk->__sk_common.skc_v6_daddr.in6_u.u6_addr32),
    77  			&sk->__sk_common.skc_v6_daddr.in6_u.u6_addr32);
    78  	}
    79  
    80  	trafficp = bpf_map_lookup_elem(&ip_map, &ip_key);
    81  	if (!trafficp) {
    82  		struct traffic_t zero;
    83  
    84  		if (receiving) {
    85  			zero.sent = 0;
    86  			zero.received = size;
    87  		} else {
    88  			zero.sent = size;
    89  			zero.received = 0;
    90  		}
    91  
    92  		bpf_map_update_elem(&ip_map, &ip_key, &zero, BPF_NOEXIST);
    93  	} else {
    94  		if (receiving)
    95  			trafficp->received += size;
    96  		else
    97  			trafficp->sent += size;
    98  
    99  		bpf_map_update_elem(&ip_map, &ip_key, trafficp, BPF_EXIST);
   100  	}
   101  
   102  	return 0;
   103  }
   104  
   105  SEC("kprobe/tcp_sendmsg")
   106  int BPF_KPROBE(ig_toptcp_sdmsg, struct sock *sk, struct msghdr *msg,
   107  	       size_t size)
   108  {
   109  	return probe_ip(false, sk, size);
   110  }
   111  
   112  /*
   113   * tcp_recvmsg() would be obvious to trace, but is less suitable because:
   114   * - we'd need to trace both entry and return, to have both sock and size
   115   * - misses tcp_read_sock() traffic
   116   * we'd much prefer tracepoints once they are available.
   117   */
   118  SEC("kprobe/tcp_cleanup_rbuf")
   119  int BPF_KPROBE(ig_toptcp_clean, struct sock *sk, int copied)
   120  {
   121  	if (copied <= 0)
   122  		return 0;
   123  
   124  	return probe_ip(true, sk, copied);
   125  }
   126  
   127  char LICENSE[] SEC("license") = "GPL";