EBPF: Cómo usar `bpf_map_update_elem` para enviar datos desde el espacio del kernel?

0

Pregunta

Estoy tratando de enviar datos (dirección IP) desde el espacio del kernel para el espacio de usuario, por la ejecución de la siguiente 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 $@

Sin embargo sigo recibiendo el siguiente error:

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

Alguien me puede ayudar a entender este error? Además, donde puedo ver la bpf_printk mensajes?

Sospecho que el archivo generado por hacer no se incluyen los EVENTS mapa.. Pero no estoy seguro de cómo solucionarlo - si puedo añadir un SEC("maps") sobre el mapa el kernel verificador ¿no busque la sección en todos..

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

Mejor respuesta

2

Te faltan:

  • SEC("maps") en el mapa de la declaración (como había adivinado).
  • La licencia de la declaración.

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

Yo era capaz de cargar y sujetar con:

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

Gracias! Donde puedo ver la printk las llamadas?
Nimrodshn

Puede utilizar bpftool prog tracelog por eso.
pchaigno

En otros idiomas

Esta página está en otros idiomas

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