Skip to content

parttimenerd/hello-ebpf

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Hello eBPF

Early Access

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. Work is on the way to work on the libbpf support in the bpf and bpf-processor modules.

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.

A sample project using the library can be found in the sample-bcc-project repository.

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 22 or later
  • libbcc (see bcc installation instructions, be sure to install the libbpfcc-dev package)
    • e.g. apt install bpfcc-tools libbpfcc-dev linux-tools-common linux-tools-$(uname -r) on Ubuntu
  • root privileges (for eBPF programs) 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 --mount-writable
limactl shell hello-ebpf sudo bin/install.sh
limactl shell hello-ebpf

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

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 22:

java -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>bcc</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:

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

BPF Examples

The examples from the book and other sources like Ansil H's blog posts are implemented in the bpf/src/main/me/bechberger/ebpf/samples directory. You can run them using the ./run_bpf.sh script. All examples have accompanying tests in the bpf/src/test directory.

Source Java Class Description
Ansil H HelloWorld A simple hello world example
Ansil H RingSample Record openat calls in a ring buffer
TypeProcessingSample RingSample using the @Type annotation
HashMapSample Record openat calls in a hash map
TypeProcessingSample RingSample using more code generation
sematext XDPPacketFilter Use XDP to block incoming packages from specific URLs

Classes and Methods

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 more features related to libbpf
    • cgroups support
    • arrays in types and array maps
  • Allow writing eBPF programs in Java
  • Drop libbcc and the BCC tools

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 -Dmaven.test.skip=false

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

./mvnw test -Djvm=testutil/bin/java -Dmaven.test.skip=false

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.

About

Hello eBPF world! Hello Java world! Let's discover eBPF together and write Java user-land library along the way.

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Contributors 4

  •  
  •  
  •  
  •