EBPF: Come utilizzare il `bpf_map_update_elem` di inviare dati dal kernel space?

0

Domanda

Sto cercando di inviare i dati (indirizzo IP) del kernel spazio per spazio utente, eseguendo il seguente BPF prorgam:

struct bpf_map_def EVENTS = {
    .type        = BPF_MAP_TYPE_HASH,
    .key_size    = sizeof(__u32),
    .value_size  = sizeof(__u32),
    .max_entries = 1,
};


SEC("xdp")
int _xdp_ip_filter(struct xdp_md *ctx) {
    bpf_printk("got a packet\n");     
    void *data_end = (void *)(long)ctx->data_end;
    void *data     = (void *)(long)ctx->data;
    struct ethhdr *eth = data;

    // check packet size
    if (eth + 1 > data_end) {
        return XDP_PASS;
    }

    // get the source address of the packet
    struct iphdr *iph = data + sizeof(struct ethhdr);
    if (iph + 1 > data_end) {
        return XDP_PASS;
    }

    __u32 ip_src = iph->saddr;
    bpf_printk("source ip address is %u\n", ip_src);

    // key of the maps
    __u32 key = 0;

    bpf_printk("starting xdp ip filter\n");
    // send the ip to the userspace program.
    bpf_map_update_elem(&EVENTS, &key, &ip_src, BPF_ANY);
    return XDP_PASS;
}

Makefile:

CLANG   ?= clang
LLC     ?= llc
OPT     ?= opt
DIS     ?= llvm-dis

ARCH    ?= $(shell uname -m | sed -e 's/aarch64/arm64/' -e 's/x86_64/x86/')
KERNEL  ?= /usr/src/linux

CFLAGS += \
    -O2 -g -emit-llvm                        \
    -D__KERNEL__                             \
    -D__BPF_TRACING__                        \
    -Wno-unused-value                        \
    -Wno-pointer-sign                        \
    -Wno-compare-distinct-pointer-types      \
    -Wno-address-of-packed-member            \
    -Wno-tautological-compare                \
    -Wno-unknown-warning-option              \
    -Wno-gnu-variable-sized-type-not-at-end  \
    -fno-asynchronous-unwind-tables

bytecode.$(ARCH).o: bytecode.c
    $(CLANG) $(CFLAGS) -c $< -o -              | \
    $(OPT) -O2 -mtriple=bpf-pc-linux           | \
    $(DIS)                                     | \
    $(LLC) -march=bpf $(LLC_FLAGS) -filetype=obj -o $@

Tuttavia continuo a ricevere il seguente messaggio di errore:

58: (85) call bpf_map_update_elem#2
R1 type=map_value expected=map_ptr
verification time 272 usec

Qualcuno mi può aiutare a capire questo errore? Inoltre dove posso vedere il bpf_printk i messaggi?

Ho il sospetto che il file generato da fare non include il EVENTS la mappa.. Ma non so come risolvere il problema - se posso aggiungere un SEC("maps") sopra la mappa del kernel verificatore non riesce a localizzare la sezione a tutti..

bpf c ebpf xdp-bpf
2021-11-24 05:42:58
1

Migliore risposta

2

Ti mancano:

  • SEC("maps") nella mappa dichiarazione (come aveva intuito).
  • La licenza dichiarazione.

#include <linux/bpf.h>
#include <linux/if_ether.h>
#include <linux/ip.h>

#include <bpf/bpf_helpers.h>

struct bpf_map_def SEC("maps") EVENTS = {
    .type        = BPF_MAP_TYPE_HASH,
    .key_size    = sizeof(__u32),
    .value_size  = sizeof(__u32),
    .max_entries = 1,
};


SEC("xdp")
int _xdp_ip_filter(struct xdp_md *ctx) {
    bpf_printk("got a packet\n");     
    void *data_end = (void *)(long)ctx->data_end;
    void *data     = (void *)(long)ctx->data;
    struct ethhdr *eth = data;

    // check packet size
    if (eth + 1 > data_end) {
        return XDP_PASS;
    }

    // get the source address of the packet
    struct iphdr *iph = data + sizeof(struct ethhdr);
    if (iph + 1 > data_end) {
        return XDP_PASS;
    }

    __u32 ip_src = iph->saddr;
    bpf_printk("source ip address is %u\n", ip_src);

    // key of the maps
    __u32 key = 0;

    bpf_printk("starting xdp ip filter\n");
    // send the ip to the userspace program.
    bpf_map_update_elem(&EVENTS, &key, &ip_src, BPF_ANY);
    return XDP_PASS;
}

char _license[] SEC("license") = "GPL";

Sono stato in grado di caricare e collegare con:

make
sudo ip link set dev wlp59s0 xdp obj ./bytecode.o sec xdp
2021-11-24 09:38:58

Grazie! Dove posso vedere il printk chiamate?
Nimrodshn

È possibile utilizzare bpftool prog tracelog per che.
pchaigno

In altre lingue

Questa pagina è in altre lingue

Русский
..................................................................................................................
Polski
..................................................................................................................
Română
..................................................................................................................
한국어
..................................................................................................................
हिन्दी
..................................................................................................................
Français
..................................................................................................................
Türk
..................................................................................................................
Česk
..................................................................................................................
Português
..................................................................................................................
ไทย
..................................................................................................................
中文
..................................................................................................................
Español
..................................................................................................................
Slovenský
..................................................................................................................