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