Search code examples
clinux-kernelebpfbpf

sk_buff filled with 0 in consume_skb tracepoint


This is sort of a follow up to a (deleted) previous question. I have discovered that the sk_buff I am trying to read is filled with 0s. Note that the following code prints 0 twice, once for the successful read, and another time for the supposed value of data_len. Am I going wrong about reading the struct, or is it just not filled on entry to the tracepoint?

SEC("tracepoint/skb/consume_skb")
int handle_skb(struct sk_buff *skb)
{
    unsigned int data_len = 1;
    long ret;

    ret = bpf_probe_read_kernel(&data_len, sizeof(data_len), &(skb->data_len));
    if (ret < 0) {
        bpf_printk("Error on probe read.n \n");
    }
    bpf_printk("ret: %d \n", ret);

    bpf_printk("len: %u \n", data_len);

    return 0;
}

(Although this code perfectly shows my problem, I have tried many different configurations without any change to the result)

The loader I am using: gist

Any help would be appreciated, thanks!

EDIT

I have tested something similar with kfree_skb, here the same problem persists. However when printing protocol available in the tracepoint I get 1 which also cannot be right.

I am now thinking this has to do with something in the setup instead of the code.


Solution

  • I think, you are using the wrong argument format for the consume_skb tracepoint. Instead of using a single sk_buff argument, try the format as reported here:

    $ cat /sys/kernel/debug/tracing/events/skb/consume_skb/format
    name: consume_skb
    ID: 1425
    format:
            field:unsigned short common_type;               offset:0;       size:2; signed:0;
            field:unsigned char common_flags;               offset:2;       size:1; signed:0;
            field:unsigned char common_preempt_count;       offset:3;       size:1; signed:0;
            field:int common_pid;                           offset:4;       size:4; signed:1;
            field:void * skbaddr;                           offset:8;       size:8; signed:0;
    
    print fmt: "skbaddr=%p", REC->skbaddr
    

    The following code shows reasonable, non-zero output for me:

    struct __attribute__((__packed__)) consume_skb_args {
            unsigned short common_type;
            unsigned char common_flags;
            unsigned char common_preempt_count;
            int common_pid;
            void *skbaddr;
    };
    
    SEC("tracepoint/skb/consume_skb")
    int tp_consume_skb(struct consume_skb_args *ctx)
    {
            char devname[IFNAMSIZ];
    
            struct sk_buff *skb = (struct sk_buff *) ctx->skbaddr;
            struct net_device *dev;
            unsigned int data_len;
    
            bpf_probe_read(&dev, sizeof(dev), &(skb->dev));
            bpf_probe_read(devname, IFNAMSIZ, &(dev->name));
            bpf_probe_read(&data_len, sizeof(data_len), &(skb->data_len));
    
            bpf_printk("skbaddr=%p dev=%s datalen=%d\n", skb, devname, data_len);
    
            return 0;
    }
    

    Ouput:

    <idle>-0       [004] ..s. 20482442.519133: 0: skbaddr=00000000d60bcc39 dev=enp2s0 datalen=1232
    <idle>-0       [004] ..s. 20482442.519183: 0: skbaddr=000000004be4ad2d dev=enp2s0 datalen=64
    <idle>-0       [004] ..s. 20482442.534944: 0: skbaddr=000000005dbe2a3e dev=enp2s0 datalen=64
    <idle>-0       [004] .Ns. 20482442.535075: 0: skbaddr=0000000068722cfa dev=enp2s0 datalen=496