1

The main issue is that I am not able to load a eBPF code in the network interface (XDP).

I am trying to load at Raspberry Pi 3, with the following configuration:

  • Raspbian GNU/Linux 10 (Buster)
  • Kernel 4.19.50-v7+

I am using ip command as follows:

$ sudo ip -force link set dev wlan0 xdp obj portfilter.o sec filter

Prior to this, I performed clang-7 installation through apt and make command is working correctly (generation the object).

The Makefile source code is as follows:

# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)

LLVM_VERSION ?= -7 #update with correct LLVM / clang version
LLVM := $(shell clang$(LLVM_VERSION) --version)
CLANG_FLAGS ?= -W -Wall \
    -Wno-compare-distinct-pointer-types

SRCS=$(wildcard *.c)
OBJS=$(patsubst %.c,%.o,$(SRCS))
Q ?= @

INCLUDE_DIRS ?= -Iheaders/

%.o: %.c
    @echo "\tLLVM CC $@"
    $(Q) clang$(LLVM_VERSION) $(INCLUDE_DIRS) -O2 -emit-llvm -c $< $(CLANG_FLAGS) -o $(patsubst %.o,%.llvm,$@)
    $(Q) llc$(LLVM_VERSION) -march=bpf -filetype=obj -o $@ $(patsubst %.o,%.llvm,$@)
    $(Q) rm $(patsubst %.o,%.llvm,$@)

ifeq ($(LLVM),)
all:
    $(warning Install LLVM to compile BPF sources)
else
all: $(OBJS)
endif

clean:
    rm -f *.llvm
    rm -f *.o

.PHONY: all clean

And portfilter.c source code that is expected to be loaded:

#include <stdbool.h>
#include <stddef.h>
#include <string.h>
#include <linux/bpf.h>
#include <linux/icmp.h>
#include <linux/if_ether.h>
#include <linux/in.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/udp.h>
#include "bpf_endian.h"
#include "bpf_helpers.h"

/* 0x3FFF mask to check for fragment offset field */
#define IP_FRAGMENTED 65343

/* Port number to be dropped */
#define PORT_DROP 80

static __always_inline int process_packet(struct xdp_md *ctx, __u64 off){

    void *data_end = (void *)(long)ctx->data_end;
    void *data = (void *)(long)ctx->data;
    struct iphdr *iph;
    struct tcphdr *tcp;
    __u16 payload_len;
    __u8 protocol;

    iph = data + off;
    if (iph + 1 > data_end)
        return XDP_PASS;
    if (iph->ihl != 5)
        return XDP_PASS;

    protocol = iph->protocol;
    payload_len = bpf_ntohs(iph->tot_len);
    off += sizeof(struct iphdr);

    /* do not support fragmented packets as L4 headers may be missing */
    if (iph->frag_off & IP_FRAGMENTED)
        return XDP_PASS;

    if (protocol == IPPROTO_TCP) {
        tcp = data + off;
        if(tcp + 1 > data_end)
            return XDP_PASS;

        /* Drop if using port PORT_DROP */
        if(tcp->source == bpf_htons(PORT_DROP) || tcp->dest == bpf_htons(PORT_DROP))
            return XDP_DROP;
        else
            return XDP_PASS;

    } else if (protocol == IPPROTO_UDP) {
        return XDP_PASS;
    }

    return XDP_PASS;
}


SEC("filter")
int pfilter(struct xdp_md *ctx){

    void *data_end = (void *)(long)ctx->data_end;
    void *data = (void *)(long)ctx->data;
    struct ethhdr *eth = data;
    __u32 eth_proto;
    __u32 nh_off;

    nh_off = sizeof(struct ethhdr);
    if (data + nh_off > data_end)
        return XDP_PASS;
    eth_proto = eth->h_proto;

    /* demo program only accepts ipv4 packets */
    if (eth_proto == bpf_htons(ETH_P_IP))
        return process_packet(ctx, nh_off);
    else
        return XDP_PASS;
}

Unfortunately, the actual output after ip command is as follows:

mkdir /sys/fs/bpf failed: Operation not permitted
Continuing without mounted eBPF fs. Too old kernel?

Prog section 'filter' rejected: Function not implemented (38)!
 - Type:         6
 - Instructions: 38 (0 over limit)
 - License:      

Verifier analysis:

Error fetching program/map!

But the expected result is the module loaded correctly in network interface.

This code is working on a laptop with Ubuntu 18 with Kernel 4.15.0-54-generic

Please, someone knows how to correctly configure the raspberry pi to work with this code ?

3
  • 1
    Just in case, did you check that your kernel has BPF support? What does grep BPF /usr/src/linux-headers-$(uname -r)/.config give you? Commented Jul 7, 2019 at 18:47
  • (Or probably your .config file is not at the location I provided -- Just follow pchaigno's instructions instead :) ) Commented Jul 7, 2019 at 19:10
  • Confirmed that a recompilation of kernel is required. The .config missing eBPF configuration Commented Jul 7, 2019 at 19:36

1 Answer 1

2

Your kernel likely isn't compiled with BPF support (my 4.15 Raspbian isn't). You can check that with the following steps:

sudo modprobe configs
zgrep -E "(BPF|XDP)" /proc/config.gz

Both CONFIG_BPF and CONFIG_BPF_SYSCALL should be enabled. If they aren't, then you need to recompile your kernel with these configs enabled.

Sign up to request clarification or add additional context in comments.

3 Comments

No zgrep on the Pi?
There is. I always forget about these commands. Fixed, thanks!
Confirmed @pchaigno inspection of .config that CONFIG_BPF = y but # CONFIG_BPF_SYSCALL is not set Then a kernel recompile was performed: $ make menuconfig Configure the following: 1) Networking support <ENTER> 2) Networking options <ENTER> 2.1) XDP sockets 2.2) BPF based packet filtering framework <Y> 2.3) enable BPF Just In Time compiler <Y> <Save> <Load> Then also configure: 1) General setup <ENTER> 1.1) Enable bpf() system call <Y> 1.2) Permanently enable BPF JIT and remove BPF interpreter (Y) <Save> <Load>

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.