Thursday, August 31, 2023

eBPF Programming Sample

In the previous post, we checked out eBPF Programming Setup. Extended Berkeley Packet Filter [eBPF] is technology that runs sandboxed programs in privileged context like the OS kernel to safely and efficiently extend the capabilities of the kernel at runtime without requiring changes to the kernel source code. One issue is there are currently limited methods to debug BPF programs thus we'd like to explore test options.

Let's check it out!

Software
Follow all instructions from the previous post to install CLion and VS Code on Ubuntu Linux. Also install the following components for low level C code unit testing, mocking and integration: Unity, CMock, Ceedling.
 Unity   Unit testing framework built for C projects with a focus on working with embedded toolchains
 CMock   Mock and stub generator and runtime for unit testing C designed to work smoothly with Unity
 Ceedling   Build system for C projects using Ruby Rake [make] build system to integrate Unity + CMock

Pre-requisites
As above, Ceedling requires Ruby installed otherwise sudo: gem: command not found errors may be thrown. Also, CMock requires Ruby bundle be installed otherwise Command 'bundle' not found errors may be thrown.
 sudo apt install ruby  sudo apt install ruby-bundler

Unity
Unity is a unit testing framework built for C, with a focus on working with embedded toolchains, which we would like to try and leverage for BPF development. Follow instructions here to install and configure Unity.
 git clone git@github.com:ThrowTheSwitch/Unity.git
 cd Unity
 cmake .
 make
 sudo make install
 sudo cp libunity.a /usr/local/lib
 sudo cp src/unity*.h /usr/local/include/unity



CMock
CMock is a mock and stub generator designed to work smoothly with Unity. CMock automagically parses the C headers and creates useful mock interfaces used for unit testing. Follow instructions here to install CMock.
 git clone --recursive https://github.com/throwtheswitch/cmock.git
 cd cmock
 bundle install


Ceedling
Ceedling is a build system for C projects using Ruby Rake [make] build system. Ceedling also makes TDD Test Driven Development simple by integrating CMock + Unity. Follow instructions here to install Ceedling.
 ruby -v
 sudo gem install ceedling




Hello Unity
In the previous post, examples installed the libbpf C-based library. Therefore, extend an example and write tests that invoke simple libbpf APIs, for example, libbpf_num_possible_cpus directly using Unity framework.

Launch CLion | New Project | C Executable | Location: /home/stevepro/HelloUnity | Language std: C11

Create

Organize src and test directory structure. Install libbpf beneath src folder. Rename main.c to all_tests.c and move beneath test folder. Update all prod and unit test code. Complete CMakeLists.txt to include library files:
 cmake_minimum_required(VERSION 3.19)
 project(HelloUnity C)
 set(CMAKE_C_STANDARD 11)
 
 include_directories(src/ /usr/local/include/unity/ src/include/libbpf/src)
 link_directories(/usr/local/lib/ src/include/libbpf/src/amd64)
 
 file(GLOB CODE_FILES src/*.c)
 file(GLOB TEST_FILES test/*.c)
 add_executable(HelloUnity ${CODE_FILES} ${TEST_FILES} )
 target_link_libraries(HelloUnity unity bpf elf z)

Edit configurations | Run with root privileges | Set breakpoints | Press F5 to debug step thru source code.



Hello CMock
At the time of writing, there is currently no way to debug BPF programs' source code interactively. Therefore, we would like to attempt to mock BPF programs or at least underlying C sourc code somehow using CMock.

Follow the example Spin up CMock. This article uses Ceedling to automate project setup and generate mocks but we will complete the following manually first to better understand the process. Original code found here.

Open folder /home/stevepro/HelloCMock. Copy inc/rectangle.h + project.yml. Execute mock command:
 ruby ~/GitHub/ThrowTheSwitch/cmock/lib/cmock.rb -oproject.yml inc/rectangle.h

This creates mocks folder two corresponding files: mock_rectangle.h and mock_rectangle.c. Notice we did not attempt to use CLion as is not currently integrated; any attempt may produce Multiple Definition issue!


Hello Ceedling
Complete previous example but this time try Ceedling using the article as a guideline: Launch the Terminal:
 cd $HOME
 ceedling new HelloCeedling

Copy all project files into src and test directories. Include inc and update project.yml with the inc directory:
  :paths:
  :test:
    - +:test/**
    - -:test/support
  :source:
    - src/**
  :include:
    - inc/**
  :support:
    - test/support
  :libraries: []

Run tests manually simply by typing ceedling

Debug tests interactively with GDB as follows: Launch VS Code. Press F5 to add launch.json file to complete:
{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "ceedling_gdb",
            "type": "cppdbg",
            "request": "launch",
            "program": "${workspaceFolder}/build/test/out/test_shape_container.out",
            "args": [],
            "stopAtEntry": false,
            "cwd": "${workspaceFolder}",
            "environment": [],
            "externalConsole": true,
            "MIMode": "gdb",
            "miDebuggerPath": "/usr/bin/gdb",
            "setupCommands": [
                {
                    "description": "Enable pretty-printing for gdb",
                    "text": "-enable-pretty-printing",
                    "ignoreFailures": true
                }
            ]
        }
    ]
}
Set breakpoint in test_shape_container.c | Press F5 to debug step thru source code:



Summary
According to ChatGPT, eBPF is versatile technology that allows safe and efficient code execution within the Linux kernel without requiring modification of kernel code. This feature makes it attractive for applications including network packet filtering, security, logging + tracing, monitoring, and performance optimization.

In summary, while eBPF is a valuable addition to the Linux ecosystem, it is not expected to replace kernel development. Instead, eBPF complements this by currently providing a flexible and efficient way to extend specific kernel features. Therefore, it will be interesting to see if this technology is dominant in the future.