bpf/socketlatency.c (183 lines of code) (raw):

/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ // +build ignore #include <vmlinux.h> #include <bpf_helpers.h> #include <bpf_tracing.h> #include <bpf_core_read.h> #include <inspector.h> char _license[] SEC("license") = "GPL"; #define LAT_THRESH_NS (1000*1000) #define LAT_THRESH_NS_10MS (10*1000*1000) #define LAT_THRESH_NS_100MS (100*1000*1000) #define ACTION_READ 1 #define ACTION_WRITE 2 #define ACTION_HANDLE 4 #define BUCKET300MS 8 #define BUCKET100MS 1 #define BUCKET10MS 2 #define BUCKET1MS 4 struct sklat_key_t { u64 createat; u64 lastreceive; u64 lastread; u64 lastwrite; u64 lastsend; } __attribute__((packed)); struct insp_sklat_event_t { char target[TASK_COMM_LEN]; struct tuple tuple; struct skb_meta skb_meta; u32 pid; u32 cpu; u32 direction; u64 latency; }; struct insp_sklat_metric_t { u32 netns; u32 pid; u32 cpu; u32 bucket; u32 action; }; struct { __uint(type, BPF_MAP_TYPE_HASH); __uint(max_entries, 10000); __type(key, struct sock *); __type(value, struct sklat_key_t); } insp_sklat_entry SEC(".maps"); struct { __uint(type, BPF_MAP_TYPE_HASH); __uint(max_entries, 4096); __type(key, struct insp_sklat_metric_t); __type(value, u64); } insp_sklat_metric SEC(".maps"); struct { __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY); } insp_sklat_events SEC(".maps"); struct insp_sklat_event_t *unused_event __attribute__((unused)); static __always_inline void report_events(struct pt_regs * ctx,struct sock * sk, u64 latency, u32 direction) { struct insp_sklat_event_t event = {0}; set_tuple_sock(sk,&event.tuple); set_meta_sock(sk,&event.skb_meta); bpf_get_current_comm(&event.target, sizeof(event.target)); event.pid = bpf_get_current_pid_tgid()>> 32; event.cpu = bpf_get_smp_processor_id(); event.latency = latency; event.direction = direction; bpf_perf_event_output((struct pt_regs *)ctx, &insp_sklat_events,BPF_F_CURRENT_CPU, &event, sizeof(event)); } SEC("kprobe/inet_ehash_nolisten") int sock_create(struct pt_regs *ctx) { struct sock * sk = (struct sock *)PT_REGS_PARM1(ctx); struct sklat_key_t ski = {0}; u64 createat = bpf_ktime_get_ns(); ski.createat = createat; bpf_map_update_elem(&insp_sklat_entry, &sk, &ski, BPF_ANY); return 0; } SEC("kprobe/sock_def_readable") int sock_receive(struct pt_regs *ctx) { struct sock * sk = (struct sock *)PT_REGS_PARM1(ctx); struct sklat_key_t * ski; u64 now; ski = bpf_map_lookup_elem(&insp_sklat_entry, &sk); if (ski) { now = bpf_ktime_get_ns(); ski->lastreceive = now; } return 0; } SEC("kprobe/tcp_cleanup_rbuf") int sock_read(struct pt_regs *ctx) { struct sock * sk = (struct sock *)PT_REGS_PARM1(ctx); int copied = (int)PT_REGS_PARM2(ctx); struct sklat_key_t * ski; ski = bpf_map_lookup_elem(&insp_sklat_entry, &sk); if (ski) { u64 now = bpf_ktime_get_ns(); if (ski->lastreceive > 0) { u64 latency; latency = now - ski->lastreceive; if (latency > LAT_THRESH_NS) { struct insp_sklat_metric_t metric = {}; metric.pid = bpf_get_current_pid_tgid()>> 32; metric.cpu = bpf_get_smp_processor_id(); metric.netns = get_sock_netns(sk); metric.bucket = BUCKET1MS; metric.action = ACTION_READ; if (latency > LAT_THRESH_NS_100MS) { metric.bucket = BUCKET100MS; report_events(ctx,sk,latency,ACTION_READ); } u64 * mtrv; mtrv = bpf_map_lookup_elem(&insp_sklat_metric, &metric); if (mtrv) { __sync_fetch_and_add(mtrv, 1); }else{ u64 initval = 1; bpf_map_update_elem(&insp_sklat_metric, &metric, &initval, BPF_ANY); } } } ski->lastread = now; } return 0; } SEC("kprobe/tcp_sendmsg_locked") int sock_write(struct pt_regs *ctx) { struct sock * sk = (struct sock *)PT_REGS_PARM1(ctx); struct sklat_key_t * ski; u64 now; ski = bpf_map_lookup_elem(&insp_sklat_entry, &sk); if (ski) { now = bpf_ktime_get_ns(); ski->lastwrite = now; } return 0; } SEC("kprobe/tcp_write_xmit") int sock_send(struct pt_regs *ctx) { struct sock * sk = (struct sock *)PT_REGS_PARM1(ctx); struct sklat_key_t * ski; u64 now; ski = bpf_map_lookup_elem(&insp_sklat_entry, &sk); if (ski){ now = bpf_ktime_get_ns(); if (ski->lastwrite > 0) { u64 latency; latency = now - ski->lastwrite; if (latency > LAT_THRESH_NS) { struct insp_sklat_metric_t metric = {}; metric.pid = bpf_get_current_pid_tgid()>> 32; metric.cpu = bpf_get_smp_processor_id(); metric.netns = get_sock_netns(sk); metric.bucket = BUCKET1MS; metric.action = ACTION_WRITE; if (latency > LAT_THRESH_NS_100MS) { metric.bucket = BUCKET100MS; report_events(ctx,sk,latency,ACTION_WRITE); } u64 * mtrv; mtrv = bpf_map_lookup_elem(&insp_sklat_metric, &metric); if (mtrv) { __sync_fetch_and_add(mtrv, 1); }else{ u64 initval = 1; bpf_map_update_elem(&insp_sklat_metric, &metric, &initval, BPF_ANY); } } } ski->lastsend = now; } return 0; } SEC("kprobe/tcp_done") int sock_destroy(struct pt_regs *ctx) { struct sock * sk = (struct sock *)PT_REGS_PARM1(ctx); bpf_map_delete_elem(&insp_sklat_entry, &sk); return 0; }