Skip to content

Instantly share code, notes, and snippets.

@theojulienne
Last active January 11, 2024 12:38
Show Gist options
  • Star 20 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save theojulienne/9d78a0cb68dbe56f19a2ae6316bc6846 to your computer and use it in GitHub Desktop.
Save theojulienne/9d78a0cb68dbe56f19a2ae6316bc6846 to your computer and use it in GitHub Desktop.
ICMP packet tracer using BCC
#!/usr/bin/python
bpf_text = """
#include <linux/ptrace.h>
#include <linux/sched.h> /* For TASK_COMM_LEN */
#include <linux/icmp.h>
#include <linux/netdevice.h>
struct probe_icmp_data_t
{
u64 timestamp_ns;
u32 tgid;
u32 pid;
char comm[TASK_COMM_LEN];
int v0;
};
BPF_PERF_OUTPUT(probe_icmp_events);
static inline unsigned char *my_skb_transport_header(const struct sk_buff *skb)
{
return skb->head + skb->transport_header;
}
static inline struct icmphdr *my_icmp_hdr(const struct sk_buff *skb)
{
return (struct icmphdr *)my_skb_transport_header(skb);
}
int probe_icmp(struct pt_regs *ctx, struct sk_buff *skb)
{
u64 __pid_tgid = bpf_get_current_pid_tgid();
u32 __tgid = __pid_tgid >> 32;
u32 __pid = __pid_tgid; // implicit cast to u32 for bottom half
struct probe_icmp_data_t __data = {0};
__data.timestamp_ns = bpf_ktime_get_ns();
__data.tgid = __tgid;
__data.pid = __pid;
bpf_get_current_comm(&__data.comm, sizeof(__data.comm));
__be16 seq;
bpf_probe_read(&seq, sizeof(seq), &my_icmp_hdr(skb)->un.echo.sequence);
__data.v0 = (int)seq;
probe_icmp_events.perf_submit(ctx, &__data, sizeof(__data));
return 0;
}
"""
from bcc import BPF
import ctypes as ct
class Data_icmp(ct.Structure):
_fields_ = [
("timestamp_ns", ct.c_ulonglong),
("tgid", ct.c_uint),
("pid", ct.c_uint),
("comm", ct.c_char * 16), # TASK_COMM_LEN
('v0', ct.c_uint),
]
b = BPF(text=bpf_text)
def print_icmp_event(cpu, data, size):
#event = b["probe_icmp_events"].event(data)
event = ct.cast(data, ct.POINTER(Data_icmp)).contents
print("%-7d %-7d %-15s %s" %
(event.tgid, event.pid,
event.comm.decode('utf-8', 'replace'),
event.v0))
b.attach_kprobe(event="icmp_echo", fn_name="probe_icmp")
b["probe_icmp_events"].open_perf_buffer(print_icmp_event)
while 1:
try:
b.kprobe_poll()
except KeyboardInterrupt:
exit()
@woodliu
Copy link

woodliu commented Jul 8, 2020

When I ran this program in linux 5.7.7(centos 7.6), I got this error:

HINT: The invalid mem access 'inv' error can happen if you try to dereference memory without first using bpf_probe_read_kernel() to copy it to the BPF stack. Sometimes the bpf_probe_read_kernel() is automatic by the bcc rewriter, other times you'll need to be explicit.
And when i change the bpf_probe_read to bpf_probe_read_kernel it works

@kongfei605
Copy link

kongfei605 commented Sep 14, 2020

replace bpf_probe_read() with

        void *addr = &my_icmp_hdr(skb)->un.echo.sequence;
        bpf_probe_read(&seq, sizeof(seq), addr);

it works for kernel 4.18.0

iovisor/bcc#3009 (comment)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment