Не удалось загрузить код eBPF / XDP на Raspberry Pi - PullRequest
0 голосов
/ 07 июля 2019

Основная проблема заключается в том, что я не могу загрузить код eBPF в сетевой интерфейс (XDP).

Я пытаюсь загрузить Raspberry Pi 3 со следующей конфигурацией:

  • Raspbian GNU / Linux 10 (Buster)
  • Ядро 4.19.50-v7 +

Я использую команду ip следующим образом:

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

До этого я выполнял установку clang-7 через apt и make команда работает правильно (генерация объекта).

Исходный код Makefile выглядит следующим образом:

# 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

И portfilter.c Исходный код, который, как ожидается, будет загружен:

#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;
}

К сожалению, фактический вывод после команды ip выглядит следующим образом:

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!

Но ожидаемый результат - модуль загружен правильно в сетевой интерфейс.

Этот код работает на ноутбуке с Ubuntu 18 с ядром 4.15.0-54-generic

Пожалуйста, кто-нибудь знает, как правильно настроить Raspberry Pi для работы с этим кодом

1 Ответ

1 голос
/ 07 июля 2019

Ваше ядро ​​, вероятно, не скомпилировано с поддержкой BPF (мой Raspbian версии 4.15 - нет).Вы можете проверить это, выполнив следующие шаги:

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

Должны быть включены оба параметра: CONFIG_BPF и CONFIG_BPF_SYSCALL.Если это не так, вам нужно перекомпилировать ядро ​​ с включенными этими конфигами.

...