BPF program using XDP returns failed to load BPF skeleton (-22) - ebpf

Firstly, I was not using the libbpf API directly, neither BCC. Instead, I was trying to use the API of the skeleton generated by bpftool.
Control code:
obj_gen = bpf_xdp_c__open();
if (!obj_gen)
goto cleanup;
ifindex = if_nametoindex("eth0");
if(!ifindex)
{
perror("if_nametoindex");
return 1;
}
err = bpf_xdp_c__load(obj_gen);
BPF code:
// Simple XDP BPF program. Everything packet will be dropped.
SEC("test")
int xdp_prog1(struct xdp_md *ctx){
char drop_message[] = "XDP PACKET DROP\n";
bpf_trace_printk(&drop_message, sizeof(drop_message));
return XDP_DROP;
}
So, after running, the error below was shown:
// libbpf: load bpf program failed: Invalid argument
// libbpf: failed to load program 'test'
// libbpf: failed to load object 'bpf_xdp_c'
// libbpf: failed to load BPF skeleton 'bpf_xdp_c': -22
After debugging, I have noticed that the program type was not with the correct value. It was always returning 0. So, I had to define the following code before the load call:
obj_gen->progs.xdp_prog1->type = BPF_PROG_TYPE_XDP;
Because the struct bpf_program was in the libbpf.c, I had to redefine in my header in in order to the compile find it. This workaround worked.
Q: Is there a better solution?

I found what it was wrong. After looking at libbpf source coude, I found the variable
static const struct bpf_sec_def section_defs[] = {... BPF_PROG_SEC("xdp",BPF_PROG_TYPE_XDP), ...
So, I noticed that I have not defined my XDP section in my BPF program with SEC("xdp").
Thanks #Qeole for your help.

Related

getting "undefined reference to ledc_cb_register" error

I'm trying to use a callback function with the led controller of esp32, however I'm unable to compile the code. I'm not sure if something is missing or the code has errors, as I have a limited understanding of pointers or coding in general.
I'm using the Arduino framework, however when I hover over the ledc_cb_register text, VSCode will popup some more details/definition of this function, so I would expect that it does see the reference to it.
relevant esp32 documentation:
docs.espressif.com
I'm trying to copy the following example, but make it a bit simpler (using only one channel):
github
It seems this example can be compiled on my side too, but this uses espidf framework.
trying the following code (many lines are not shown here for simplicity)
static bool cb_ledc_fade_end_event(const ledc_cb_param_t *param, void *user_arg)
{
portBASE_TYPE taskAwoken = pdFALSE;
if (param->event == LEDC_FADE_END_EVT) {
isFading = false;
}
return (taskAwoken == pdTRUE);
}
[...]
void setup() {
ledc_timer_config_t ledc_timer = {
.speed_mode = LEDC_HIGH_SPEED_MODE, // timer mode
.duty_resolution = LEDC_TIMER_13_BIT, // resolution of PWM duty
.timer_num = LEDC_TIMER_0, // timer index
.freq_hz = LED_frequency, // frequency of PWM signal
.clk_cfg = LEDC_AUTO_CLK, // Auto select the source clock
};
ESP_ERROR_CHECK(ledc_timer_config(&ledc_timer));
ledc_channel_config_t ledc_channel = {
.gpio_num = LED_PIN,
.speed_mode = LEDC_HIGH_SPEED_MODE,
.channel = LEDC_CHANNEL_0,
.timer_sel = LEDC_TIMER_0,
.duty = 4000,
.hpoint = 0,
//.flags.output_invert = 0
};
ESP_ERROR_CHECK(ledc_channel_config(&ledc_channel));
ledc_fade_func_install(0);
ledc_cbs_t callbacks = {
.fade_cb = cb_ledc_fade_end_event
};
ledc_cb_register(LEDC_HIGH_SPEED_MODE, LEDC_CHANNEL_0, &callbacks, 0);
and getting the following error message:
[..]/.platformio/packages/toolchain-xtensa-esp32#8.4.0+2021r2-patch3/bin/../lib/gcc/xtensa-esp32-elf/8.4.0/../../../../xtensa-esp32-elf/bin/ld.exe: .pio\build\esp32dev\src\main.cpp.o:(.literal._Z5setupv+0x78): undefined reference to 'ledc_cb_register(ledc_mode_t, ledc_channel_t, ledc_cbs_t*, void*)'
[..]/.platformio/packages/toolchain-xtensa-esp32#8.4.0+2021r2-patch3/bin/../lib/gcc/xtensa-esp32-elf/8.4.0/../../../../xtensa-esp32-elf/bin/ld.exe: .pio\build\esp32dev\src\main.cpp.o: in function 'setup()':
[..]\PlatformIO\Projects\asdf/src/main.cpp:272: undefined reference to 'ledc_cb_register(ledc_mode_t, ledc_channel_t, ledc_cbs_t*, void*)'
collect2.exe: error: ld returned 1 exit status
*** [.pio\build\esp32dev\firmware.elf] Error 1
According to the docs, it seems to be a feature that was added in v4.4.4
but the latest Arduino core (2.0.6) is build on v4.4.3.
If you are not on the latest Arduino core, try updating that first and see if it works. If not, then you just have to wait until the Arduino core is updated to use ESP IDF v4.4.4.
Of course, you can use ledc_isr_register(...) to register an ISR handler for the interrupt.
Best of luck!
Update:
I realized that the problem (at least on my side when testing it) was that there is an error in the ledc.h file, where they forgot to add ledc_cb_register in an extern "C" block.
I manually patched it by moving the
#ifdef __cplusplus
}
#endif
part, which was located after the ledc_set_fade_step_and_start function, below ledc_cb_register instead.
So, the end of my ledc.h file looks like this now:
...
esp_err_t ledc_set_fade_step_and_start(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t target_duty, uint32_t scale, uint32_t cycle_num, ledc_fade_mode_t fade_mode);
/**
* #brief LEDC callback registration function
* ...
*/
esp_err_t ledc_cb_register(ledc_mode_t speed_mode, ledc_channel_t channel, ledc_cbs_t *cbs, void *user_arg);
#ifdef __cplusplus
}
#endif

pcap_getnonblock() returns -3

I am quite new to using pcap lib, so please bear with me.
I am trying to use pcap_getnonblock function, the documentation says the following:
pcap_getnonblock() returns the current 'non-blocking' state of
the capture descriptor; it always returns 0 on 'savefiles' . If
there is an error, PCAP_ERROR is returned and errbuf is filled in
with an appropriate error message.
errbuf is assumed to be able to hold at least PCAP_ERRBUF_SIZE
chars.
I got -3 returned and the errbuf is an empty string, I couldn't understand the meaning of such result.
I believe this caused a socket error: 10065.
This problem happened only once and I could not reproduce it, but still it would be great to find its causing to prevent it in future executions.
Thanks in advance.
pcap_getnonblock() can return -3 - that's PCAP_ERROR_NOT_ACTIVATED. Unfortunately, that's not documented; I'll fix that.
Here's a minimal reproducible example that demonstrates this:
#include <pcap/pcap.h>
#include <stdio.h>
int
main(int argc, char **argv)
{
pcap_t *pcap;
char errbuf[PCAP_ERRBUF_SIZE];
if (argc != 2) {
fprintf(stderr, "Usage: this_program <interface_name>\n");
return 1;
}
pcap = pcap_create(argv[1], errbuf);
if (pcap == NULL) {
fprintf(stderr, "this_program: pcap_create(%s) failed: %s\n",
argv[1], errbuf);
return 2;
}
printf("pcap_getnonblock() returns %d on non-activated pcap_t\n",
pcap_getnonblock(pcap, errbuf));
return 0;
}
(yes, that's minimal, as 1) names of interfaces are OS-dependent, so it has to be a command-line argument and 2) if you don't run the program correctly, it should let you know what's happening, so you know what you have to do in order to reproduce the problem).
Perhaps pcap_getnonblock() and pcap_setnonblock() should be changed so that you can set non-blocking mode before activating the pcap_t, so that, when activated, it will be in non-blocking mode. It doesn't work that way currently, however.
I.e., you're allocating a pcap_t with pcap_create(), but you're not activating it with pcap_activate(). You need to do both in order to have a pcap_t on which you can capture.

XDP and sk_buff

I started coding in ebpf and XDP.
I am using python bcc to load the XDP program to the NICs.
I am trying to work with __sk_buff structure, but when I am trying to access any filed of skb the verifier failed to load the program.
int xdp_test(struct sk_buff *skb)
{
void *data = (void*)(long)skb->data;
void *data_end = (void*)(long)skb->data_end;
if (data + sizeof(struct ethhdr) + sizeof(struct iphdr) < data_end)
{
struct iphdr * ip = ip_hdr(skb);
// according to my checks, it failed because of this line. I cant access to ip->protocol (or any other fileds)
if (ip->protocol == IPPROTO_TCP)
{
return XDP_PASS;
}
}
...
return XDP_PASS
}
I just want to calculates layer 4 checksum on my program using bpf_l4_csum_replace Which takes skb as the first argument.
Why is that happening?
Can I even use __sk_buff structure in XDP? Or I have to use the xdp_md struct?
UPDATE:
Thanks to Qeole, I understood that I cannot use sk_buff using XDP.
There is a way to calculate TCP checksum using xdp_md?
Indeed you cannot use the struct __sk_buff in XDP programs. You have to use the struct xdp_md instead. XDP performance is due for a great part to the kernel calling the eBPF program before the allocation and initialisation of the socket buffer (struct sk_buff in the kernel), which saves time and resources, but also means you don't have access to that structure in your XDP program.

BPF Ring Buffer Invalid Argument (-22)?

I wanted to use eBPF's latest map, BPF_MAP_TYPE_RINGBUF, but I can't find much information online on how I can use it, so I am just doing some trial-and-error here. I defined and used it like this:
struct bpf_map_def SEC("maps") r_buf = {
.type = BPF_MAP_TYPE_RINGBUF,
.max_entries = 1 << 2,
};
SEC("lsm/task_alloc")
int BPF_PROG(task_alloc, struct task_struct *task, unsigned long clone_flags) {
uint32_t pid = task->pid;
bpf_ringbuf_output(&r_buf, &pid, sizeof(uint32_t), 0); //stores the pid value to the ring buffer
return 0;
}
But I got the following error when running:
libbpf: map 'r_buf': failed to create: Invalid argument(-22)
libbpf: failed to load object 'bpf_example_kern'
libbpf: failed to load BPF skeleton 'bpf_example_kern': -22
It seems like libbpf does not recognize BPF_MAP_TYPE_RINGBUF? I cloned the latest libbpf from GitHub and did make and make install. I am using Linux 5.8.0 kernel.
UPDATE: The issue seems to be resolved if I changed the max_entries to something like 4096 * 64, but I don't know why this is the case.
You are right, the problem is in the size of BPF_MAP_TYPE_RINGBUF (max_entries attribute in libbpf map definition). It has to be a multiple of a memory page (which is 4096 bytes at least on most popular platforms). So that explains why it all worked when you specified 64 * 4096.
BTW, if you'd like to see some examples of using it, I'd start with BPF selftests:
user-space part: https://github.com/torvalds/linux/blob/master/tools/testing/selftests/bpf/prog_tests/ringbuf.c
kernel (BPF) part: https://github.com/torvalds/linux/blob/master/tools/testing/selftests/bpf/progs/test_ringbuf.c

I have an error trying to access iphdr using eBPF

So I've been trying to access the iphdr using eBPF.
static inline int parse_ipv4(void *data, u64 nh_off, void *data_end) {
struct iphdr *iph = data + nh_off;
if ((void*)&iph[1] > data_end)
return 0;
return iph->protocol;
}
When I use the code above in the eBPF function, it works fine like :
if (h_proto == htons(ETH_P_IP)){
index = parse_ipv4(data, nh_off, data_end);
Like this, calling parse_ipv4 function works.
However, if I try to access the ipheader directly without using the function, it doesn't work.
if (h_proto == htons(ETH_P_IP)){
index = parse_ipv4(data, nh_off, data_end);
struct iphdr *iph2 = sizeof(*eth) + nh_off;
}
This gives me an error : HINT: The invalid mem access 'inv' error can happen if you try to dereference memory without first using bpf_probe_read() to copy it to the BPF stack. Sometimes the bpf_probe_read is automatic by the bcc rewriter, other times you'll need to be explicit.
and fails to activate.
Thank you so much in advance!
Unless I misunderstand your program, the following:
struct iphdr *iph2 = sizeof(*eth) + nh_off;
looks erroneous. Instead, iph2 should be something like data + nh_off, just as in your function, no? If you set it to the sum of two sizes, without any base address, then you try to access data at an arbitrary memory location (something like 0x28 I guess), which of course is not permitted.