1

If I want to write a cBPF program which filter icmp packet I can do it by execute tcpdump with -dd option which

Dump packet-matching code as a C program fragment.

..see the example below

How can I write the same program with eBPF instructions ?

#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <linux/if_ether.h>
/* ... */

/* From the example above: tcpdump -i lo icmp -dd */
struct sock_filter code[] = {
{ 0x28, 0, 0, 0x0000000c },
{ 0x15, 0, 3, 0x00000800 },
{ 0x30, 0, 0, 0x00000017 },
{ 0x15, 0, 1, 0x00000001 },
{ 0x6, 0, 0, 0x00040000 },
{ 0x6, 0, 0, 0x00000000 },
};

struct sock_fprog bpf = {
    .len = ARRAY_SIZE(code),
    .filter = code,
};

sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if (sock < 0)
    /* ... bail out ... */

ret = setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &bpf, sizeof(bpf));
if (ret < 0)
    /* ... bail out ... */

/* ... */
close(sock);
Maicake
  • 1,046
  • 10
  • 34

1 Answers1

1

You can pass eBPF instructions in a way very similar to what you do for your cBPF program: you can have something like

struct bpf_insn ebpf_code[] = {
{ 0xb7, 0, 0, 0, 0 },
{ 0x95, 0, 0, 0, 0 },
};

(Note the length of the instructions is not the same as for cBPF.)

But there is no tool, at this time, that will dump the instructions for you just like tcpdump -dd does. This means you have to build your program another way.

One solution is to write the eBPF instructions yourself. This is pretty much like programming in assembly. You have some documentation for BPF in the kernel, or a list of the existing instructions and their syntax here.

Because writing manually the individual eBPF instructions is not fun[citation needed], the typical workflow for eBPF is somewhat different. clang/LLVM has a back-end for eBPF, and most eBPF programs built today rely on it. The workflow looks like this:

  1. Write your BPF program in C.
  2. Compile it with clang/LLVM into an object file (ELF).
  3. Load the bytecode from your object file with a tool or library (ip link, tc filter, bpftool, bcc, libbpf, gobpf, ...).
  4. Inject the bytecode into the kernel and attach it to a hook (e.g. a socket) (this is generally done by the same tools or libraries).

The kernel has a bunch of sample BPF programs written in C. You can have a look and see if one of them can be adapted to your needs. What you need to implement is probably something along:

  1. Check your packet is long enough to have a full Ethernet header.
  2. Check that ethertype is IPv4.
  3. Check that following the Ethernet header, your packet is long enough to have a full IPv4 header.
  4. Check that IP protocol number is ICMP.

Then return the action related to what you want to do with that packet (the value depends on what hook, socket/TC/XDP, you attach your program to).

Qeole
  • 8,284
  • 1
  • 24
  • 52
  • Thanks for your answer, I'd ask you another 10000 things can I write you in pm? Do you have some link where I can learn how to write ebpf program in C? I mean, I can't find a "friendly" guide. XD – Maicake Jul 16 '19 at 08:43
  • Sure, feel free to send your questions! But keep in mind that it's nice to ask the generic one here as well, so that others can benefit from the answers too :). There is a bunch of links to BPF resources [on this page](https://github.com/zoidbergwill/awesome-ebpf), some more complete (Cilium guide in particular), some more accessible. To get started with network processing, I'd recommend having a look at Jesper's [tutorials on XDP](https://github.com/xdp-project/xdp-tutorial/tree/master/packet01-parsing) (most of it applies to other network hooks too). – Qeole Jul 16 '19 at 08:54
  • Thanks again. If u can look at this it would be great https://stackoverflow.com/questions/57053518/why-this-program-which-use-bpf-and-raw-socket-just-hangs I'm trying to write a simple bpf program. But It doesn't work. – Maicake Jul 16 '19 at 09:18
  • I have a doubt, why I can pass ebpf instruction which are longer than cbpf, using the same struct sock_filter ? – Maicake Jul 19 '19 at 11:42
  • Yes, my bad, I did some over-simplification there. It wouldn't be a `struct sock_filter` at all, it would be an array of `struct bpf_insn` as defined in /usr/include/linux/bpf.h (I'll edit the answer), and you would eventually need to load it via the `bpf()` system call (libbpf provides useful helpers around it, for the record). You have examples in the [kernel repository](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/samples/bpf/sock_example.c), if you want to have a look. But honestly the typical eBPF workflow is compiling from C, it's much easier this way. – Qeole Jul 19 '19 at 12:37
  • thanks for the clarification. do you have a complete example which explains also how to compile the restricted C out of the kernel tree ? Or I have to download all the kernel source code in any case? – Maicake Jul 19 '19 at 13:38
  • You don't have to download the kernel code. Did you have a look at [the tutorials](https://github.com/xdp-project/xdp-tutorial/tree/master/packet01-parsing) I linked above? It's probably one of the best places to get started. We (my company) also have some [out-of-tree samples](https://github.com/Netronome/bpf-samples/), slightly more complex but hopefully still accessible to newcomers. – Qeole Jul 19 '19 at 14:26
  • Thanks. Is mandatory to use xdp to filter packets or is just to filter at a lower level? I've tried to contact you at the email showed on your website but I think you don't use it anymore. – Maicake Jul 19 '19 at 16:36
  • Not mandatory to use XDP. Alternatives are TC (traffic control hook) or socket-level. I did receive your email and will respond, just haven't found the time so far :). – Qeole Jul 20 '19 at 15:58