iovisor / bcc

BCC - Tools for BPF-based Linux IO analysis, networking, monitoring, and more
Apache License 2.0
20.58k stars 3.88k forks source link

bpf tasks #574

Open 4ast opened 8 years ago

4ast commented 8 years ago

bpf core

bpf tracing

bpf llvm

bpf security

bpf testing

xdp

janrueth commented 8 years ago

Hi,

I added xdp support to bcc, if there is an interest I can file a pull request! (https://github.com/Eichhoernchen/bcc/commit/43462f45457e3221d61307c6c44e1aaeffa09235)

Todo so I added a method attach_xdp that takes a function and an interface name as an argument. Here is an example (I used the xdp1_kern.c example from the xdp devel branch):

from bcc import BPF
import time

# load BPF program
b = BPF(text = """
    #include <uapi/linux/bpf.h>
    #include <linux/in.h>
    #include <linux/if_ether.h>
    #include <linux/if_packet.h>
    #include <linux/if_vlan.h>
    #include <linux/ip.h>
    #include <linux/ipv6.h>

    BPF_TABLE("percpu_array", uint32_t, long, dropcnt, 256);

    static inline int parse_ipv4(void *data, u64 nh_off, void *data_end)
    {
        struct iphdr *iph = data + nh_off;

        if ((void*)&iph[1] > data_end)
            return 0;
        return iph->protocol;
    }

    static inline int parse_ipv6(void *data, u64 nh_off, void *data_end)
    {
        struct ipv6hdr *ip6h = data + nh_off;

        if ((void*)&ip6h[1] > data_end)
            return 0;
        return ip6h->nexthdr;
    }

    int xdp_prog1(struct xdp_md *ctx) {

        void* data_end = (void*)(long)ctx->data_end;
        void* data = (void*)(long)ctx->data;

        struct ethhdr *eth = data;

        // drop packets
        int rc = XDP_DROP; // let pass XDP_PASS or redirect to tx via XDP_TX
        long *value;
        uint16_t h_proto;
        uint64_t nh_off = 0;
        uint32_t index;

        nh_off = sizeof(*eth);

        if (data + nh_off  > data_end)
            return rc;

        h_proto = eth->h_proto;

        if (h_proto == htons(ETH_P_8021Q) || h_proto == htons(ETH_P_8021AD)) {
            struct vlan_hdr *vhdr;

            vhdr = data + nh_off;
            nh_off += sizeof(struct vlan_hdr);
            if (data + nh_off > data_end)
                return rc;
                h_proto = vhdr->h_vlan_encapsulated_proto;
        }
        if (h_proto == htons(ETH_P_8021Q) || h_proto == htons(ETH_P_8021AD)) {
            struct vlan_hdr *vhdr;

            vhdr = data + nh_off;
            nh_off += sizeof(struct vlan_hdr);
            if (data + nh_off > data_end)
                return rc;
                h_proto = vhdr->h_vlan_encapsulated_proto;
        }

        if (h_proto == htons(ETH_P_IP))
            index = parse_ipv4(data, nh_off, data_end);
        else if (h_proto == htons(ETH_P_IPV6))
           index = parse_ipv6(data, nh_off, data_end);
        else
            index = 0;

        value = dropcnt.lookup(&index);
        if (value)
            *value += 1;

        return rc;
    }

    """)

xdp_func = b.load_func("xdp_prog1", BPF.XDP)
b.attach_xdp(xdp_func, "enp0s3")
dropcnt = b.get_table("dropcnt")

while 1:
    for k in dropcnt.keys():
        if (dropcnt.sum(k).value > 0):
            print("{}: {}".format(k.value, dropcnt.sum(k).value))
    time.sleep(1)

I'm still undecided if I prefer having the interface before the function...

I basically refactored and adapted parts of xdp1_user.c for libbpf.

4ast commented 8 years ago

nice! the first xdp patch set is close enough to net-next. Looking forward to your PR as soon as it lands, since there still can be minor changes in uapi. Like the most recent addition of XDP_ABORT. Thanks!

janrueth commented 8 years ago

cool, I will be monitoring the changes and merge them and once xdp is in net-next I'll file a PR

4ast commented 7 years ago

cc @brendangregg please add to the wish list :)

borkmann commented 7 years ago
borkmann commented 7 years ago
borkmann commented 7 years ago

bpf testing