#!/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()