Reputation: 48
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:
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 ?
Upvotes: 1
Views: 2839
Reputation: 13133
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.
Upvotes: 2