/hello-ebpf

Hello eBPF world! Hello Java world! Let's discover eBPF together and write Java bindings for BCC along the way.

Primary LanguageJavaApache License 2.0Apache-2.0

Hello eBPF

ci

There are user land libraries for eBPF that allow you to write eBPF applications in C++, Rust, Go, Python and even Lua. But there are none for Java, which is a pity. So... I decided to write bindings using Project Panama and bcc, the first and widely used userland library for eBPF, which is typically used with its Python API.

Overview images

Based on the overview from ebpf.io, duke image from OpenJDK.

Hello eBPF world! Hello Java world!

Let's discover eBPF together. Join me on the journey to write all examples from the Learning eBPF book (get it also from Bookshop.org, Amazon, or O'Reilly), by Liz Rice in Java, implementing a Java userland library for eBPF along the way, with a blog series to document the journey.

This project is still in its early stages, and a read-along of the book is recommended:

We're currently at page 23 of the book in the blog series and page 36 with this repo.

It is evolving fast, you can already implement all examples and exercises from chapter 2.

Goals

Provide a library (and documentation) for Java developers to explore eBPF and write their own eBPF programs, and the examples from the book without having to Python.

The initial goal is to be as close to bcc Python API as possible so that the examples from the book can be ported to Java easily.

You can find the Java versions of the examples in the bcc/src/main/me/bechberger/samples and the API in the bcc/src/main/me/bechberger/bcc directory.

Prerequisites

These might change in the future, but for now, you need the following:

Either a Linux machine with the following:

  • Linux 64-bit (or a VM)
  • Java 21 (exactly this version, as we need Project Panama with is a preview feature), we'll switch to Java 22 as soon as it is released
  • libbcc (see bcc installation instructions, be sure to install the libbpfcc-dev package)
  • root privileges (for eBPF programs)
  • Maven 3.6.3 (or newer to build the project)

On Mac OS, you can use the Lima VM (or use the hello-ebpf.yaml file as a guide to install the prerequisites):

limactl start hello-ebpf.yaml
limactl shell hello-ebpf

# You'll need to be root for most of the examples
sudo -s

Build

To build the project, make sure you have all prerequisites installed, then just run:

./build.sh

Running the examples

Be sure to run the following in a shell with root privileges that uses JDK 21:

java --enable-preview -cp bcc/target/bcc.jar --enable-native-access=ALL-UNNAMED me.bechberger.ebpf.samples.EXAMPLE_NAME
# or in the project directory
./run.sh EXAMPLE_NAME

# list all examples
./run.sh

The following runs the hello world sample from the vcc repository. It currently prints something like:

> ./run.sh bcc.HelloWorld
           <...>-30325   [042] ...21 10571.161861: bpf_trace_printk: Hello, World!
             zsh-30325   [004] ...21 10571.164091: bpf_trace_printk: Hello, World!
             zsh-30325   [115] ...21 10571.166249: bpf_trace_printk: Hello, World!
             zsh-39907   [127] ...21 10571.167210: bpf_trace_printk: Hello, World!
             zsh-30325   [115] ...21 10572.231333: bpf_trace_printk: Hello, World!
             zsh-30325   [060] ...21 10572.233574: bpf_trace_printk: Hello, World!
             zsh-30325   [099] ...21 10572.235698: bpf_trace_printk: Hello, World!
             zsh-39911   [100] ...21 10572.236664: bpf_trace_printk: Hello, World!
 MediaSu~isor #3-19365   [064] ...21 10573.417254: bpf_trace_printk: Hello, World!
 MediaSu~isor #3-22497   [000] ...21 10573.417254: bpf_trace_printk: Hello, World!
 MediaPD~oder #1-39914   [083] ...21 10573.418197: bpf_trace_printk: Hello, World!
 MediaSu~isor #3-39913   [116] ...21 10573.418249: bpf_trace_printk: Hello, World!

The related code is (chapter2/HelloWorld.java):

public class HelloWorld {
  public static void main(String[] args) {
    try (BPF b = BPF.builder("""
            int hello(void *ctx) {
               bpf_trace_printk("Hello, World!");
               return 0;
            }
            """).build()) {
      var syscall = b.get_syscall_fnname("execve");
      b.attach_kprobe(syscall, "hello");
      b.trace_print();
    }
  }
}

Which is equivalent to the Python code and prints "Hello, World!" for each execve syscall:

from bcc import BPF

program = r"""
int hello(void *ctx) {
    bpf_trace_printk("Hello World!");
    return 0;
}
"""

b = BPF(text=program)
syscall = b.get_syscall_fnname("execve")
b.attach_kprobe(event=syscall, fn_name="hello")

b.trace_print()

You can use the debug.sh to run an example with a debugger port open at port 5005.

Usage as a library

The library is available as a Maven package:

<dependency>
    <groupId>me.bechberger</groupId>
    <artifactId>hello-ebpf</artifactId>
    <version>0.1.0-SNAPSHOT</version>
</dependency>

You might have to add the https://s01.oss.sonatype.org/content/repositories/releases/ repo:

<repositories>
    <repository>
        <id>snapshots</id>
        <url>https://s01.oss.sonatype.org/content/repositories/snapshots/</url>
        <releases>
            <enabled>false</enabled>
        </releases>
        <snapshots>
            <enabled>true</enabled>
        </snapshots>
    </repository>
</repositories>

Blog Posts

Posts covering the development of this project:

Planned posts:

  • Hello eBPF: Recording data in perf buffers and program arrays (3)

Examples

We implement the Java API alongside implementing the examples from the book, so we track the progress of the implementation by the examples we have implemented. We also use examples from different sources like the bcc repository and state this in the first column.

Chapter
/Source
Example Java class Status Description
bcc bcc/hello_world.py HelloWorld works Basic hello world
2 chapter2/hello.py chapter2.HelloWorld works print "Hello World!" for each execve syscall
2 chapter2/hello-map.py chapter2.HelloMap works Count and print execve calls per user
own - own.HelloStructMap works Count and print execve calls per user and store the result as a struct in a map
2 chapter2/hello-buffer.py chapter2.HelloBuffer works Record information in perf buffer
2 chapter2/hello-tail.py chapter2.HelloTail works Print a message when a syscall is called, and also when a timer is created or deleted.
2 - chapter2.ex works Implementation of some of the exercises for chapter 2
own own/disassembler-test.py own.DisassemblerTest works Disassemble byte-code for the HelloMap example

... more to come from the books' repository.

Classes

All classes and methods have the name as in the Python API, introducing things like builders only for more complex cases (like the constructor of BPF).

The comments for all of these entities are copied from the Python API and extended where necessary.

Plans

A look ahead into the future so you know what to expect:

  • Implement the API so that we can recreate all bcc examples from the book
  • Make it properly available as a library on Maven Central
  • Support the newer libbpf library
  • Allow writing eBPF programs in Java

These plans might change, but I'll try to keep this up to date. I'm open to suggestions, contributions, and ideas.

Other modules

Testing

Tests are run using JUnit 5 and ./mvnw test. You can either run

./mvnw test

or you can run the tests in a container using testutil/bin/java:

./mvnw test -Djvm=testutil/bin/java

This requires virtme (apt install virtme), python 3, and docker to be installed. You can run custom commands in the container using testutil/run-in-container.sh. Read more in the testutil/README.md.

I'm unable to get it running in the CI, so I'm currently running the tests locally.

Contributing

Contributions are welcome; just open an issue or a pull request. Discussions take place in the discussions section of the GitHub repository.

I'm happy to include more example programs, API documentation, or helper methods, as well as links to repositories and projects that use this library.

License

Apache 2.0, Copyright 2023 SAP SE or an SAP affiliate company, Johannes Bechberger and contributors

This is a side project. The amount of time I can invest might vary over time.