Offloaded XDP program to Netronome Smart NIC unsupported function
I'm trying to offload a small EBPF program to the NIC that uses a map. I can lookup elements in the hash map, but when I add the command bpf_map_update_elem I get back an error when I attempt to load.
14: (85) call bpf_map_update_elem#2
[nfp] map_update: not supported by FW
The driver I'm running:
$ ethtool -i $ETHNAME
driver: nfp
version: 5.15.0-27-generic
firmware-version: 0.0.3.5 0.31 bpf-2.0.6.124 ebpf
expansion-rom-version:
bus-info: 0000:06:00.0
supports-statistics: yes
supports-test: no
supports-eeprom-access: no
supports-register-dump: yes
supports-priv-flags: no
According to https://www.netronome.com/media/documents/UG_Getting_Started_with_eBPF_Offload.pdf this function should be supported. Has anybody found a solution?
1 answer
-
answered 2022-05-04 10:05
Qeole
The document you link states:
Since Kernel 4.17, map updates are supported by our driver. As of this writing, our public firmware does not contain map update support from the datapath, but this is available on request.
You should contact Netronome's customer support service to get the version of the firmware which supports map updates.
(I worked on this guide and can confirm that, to my knowledge, the firmware with map updates has not been publicly released.)
do you know?
how many words do you know
See also questions close to this topic
-
Use of function kmem_cache_shrink() in slab allocation
While going through the slab allocation mechanism, I came across the following function.
int kmem_cache_shrink (struct kmem_cache *)
The description of this function can be found here.
The description only tells that this function is used to release as many slabs from the cache created. I think that the slabs which will have "empty" status will be only released.
Under what scenarios do we need this function?
Any inputs on this will be helpful.
-
Specifying an "Address Space layout" for a binary
First of all, I don't simply want to "turn off" Address Space Layout Randomization (ASLR). I already know how to know that. My issue is a bit more complicated.
Without going into unnecessary details and reasons for the weird request, I would like a binary to be loaded at addresses that I control. Not just the same address every time I run it like no-ASLR, but rather, an address of my choice which may change between runs. I can only think of two ways to do this:
- Explicitly let the kernel know that I want the binary loaded at some specific address. I have been googling for a while and I am not sure if this is even possible. But on the hopes that I am wrong, is there a way to do this?
- Compile the application from the beginning with specific addresses, which I wouldn't mind doing between runs. For example, take the following simple asm program (I know it will segfault, doesn't matter for now), is there a way to specify an absolute address for the .text section or the _start label? Either through the assembler itself
as
or the linkerld
?
.section .text .global _start _start: jmp 0x0
Is one of those two ways possible? Any other possible solutions to this problem? My OS is Linux, and I use GCC as my compiler.
-
Bypass proc_dointvec_minmax in kernel to allow other values
I am looking for a way to bypass a limit that is implemented the same way as the following
kexec_load_disabled: { .procname = "kexec_load_disabled", .data = &kexec_load_disabled, .maxlen = sizeof(int), .mode = 0644, /* only handle a transition from default "0" to "1" */ .proc_handler = proc_dointvec_minmax, .extra1 = &one, .extra2 = &one, },
I have root access and I can load kernel modules aswell. I can use
/proc/kallsyms
to find the address of proc_dointvec_minmax, so I suppose I can somehow manage to write a kernel module that when loaded is able to overwrite the function so it allows going back to 0 again, then set the value to 0 and restore the original instructions? I assume I need to reconfigure the MMU first to allow writes to the kernel instructions? Or can I somehow add a breakpoint in proc_dointvec_minmax so that when it's hit I grab the arguments and modify those? Once I have a starting point I should be able to continue on my own, but right now I am not sure about what approach to choose/what the easiest way to solve it would be. -
Network Device Driver: Strange ping time statistics
I have developed a network driver, initialized as follow:
dev = alloc_etherdev_mqs(64, 1000, 500); dev->header_ops = NULL; dev->mtu = 1500; dev->tx_queue_len = 1000; dev->watchdog_timeo = 1*HZ; /* net driver is a pure IP device */ dev->flags = IFF_NOARP & (~IFF_BROADCAST & ~IFF_MULTICAST); /* not support VLAN */ dev->features = NETIF_F_VLAN_CHALLENGED; /* enable hw gather/scatter for checksums computation */ dev->features |= NETIF_F_SG; dev->hw_features |= NETIF_F_SG; dev->addr_len = ETH_ALEN; /* ethernet header size */ #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 9) dev->destructor = free_netdev; #else dev->priv_destructor = free_netdev; #endif dev->netdev_ops = ops; random_ether_addr((u8 *) dev->dev_addr); #ifdef LINUX_VERSION_CODE > KERNEL_VERSION(4, 13, 0) dev->type = ARPHRD_RAWIP; #else dev->type = ARPHRD_NONE; #endif snprintf(dev->name, IFNAMSIZ, "if0");
i have also implemented some of struct net_device_ops callbacks
static struct net_device_ops tz_netdev_ops = { .ndo_open = dev_ops_open, .ndo_stop = dev_ops_close, .ndo_start_xmit = dev_ops_start_xmit, .ndo_tx_timeout = dev_ops_tx_timeout, .ndo_do_ioctl = dev_ops_ioctl, .ndo_change_mtu = dev_ops_change_mtu, .ndo_select_queue = dev_ops_select_queue };
When i make ifconfig if0 192.168.1.2, then i try to ping the gateway 192.168.1.1, the round trip time displayed by the ping command is the difference between the reception of the last response packet and the first request packet.
if i have two packets sent per second, the ping display the sum of the round trip of the two packets as follow
PING 192.168.1.1 (192.168.1.1): 56 data bytes 62.003832912 dev_ops_start_xmit: new packet to send 62.005227344 tx_worker: send packet 62.049803696 rx_worker: receive packet from internet, deliver packet to upper layer 62.050698640 handle_rx_done: deliver packet len: 84 to upper layer 62.057168992 dev_ops_start_xmit: new packet to send 62.059391744 tx_worker: send packet 62.191116928 rx_worker: receive packet from internet, deliver packet to upper layer 62.192112848 handle_rx_done: deliver packet len: 84 to upper layer 64 bytes from 192.168.1.1: seq=0 ttl=64 time=195.076 ms
so the time displayed by the ping command is: 62.192112848 - 62.003832912 + delta(t)
seems, that the flow is aggregated, any idea to understand this behavior?
-
Accessing system RAM from linux driver
I have reserved memory using the device tree as follows:
list_reserved: list@0x1F028000 { reg = <0x1F028000 0x12C000>; no-map; };
I am using ioremap to map the memory
ioremap_wt(mem->start,resource_size(mem));
- For reading I use ioread32 and it works.
- For writing I use iowrite32 but fails abruptly. After writing when I check the memory, I could see the data written in a patterned way. It writes in every 4th word which I could not understand why or find a way to solve it.
-
I'm not receiving packets using XDP_TX
// SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) // Copyright (c) 2018 Netronome Systems, Inc. #define BPF_NO_GLOBAL_DATA #define MAX_PACKET_OFF 0xffff #include <stdbool.h> #include <stddef.h> #include <string.h> #include <linux/bpf.h> #include <linux/icmp.h> #include <linux/if_ether.h> #include <linux/if_vlan.h> #include <linux/in.h> #include <linux/ip.h> #include <linux/tcp.h> #include <linux/udp.h> #include <linux/ipv6.h> #include "bpf_endian.h" #include "bpf_helpers.h" #include "jhash.h" #include "common.h" #include "parsing_helpers.h" #include <stdint.h> SEC("prog") int xdp_drop_benchmark_traffic(struct xdp_md* ctx) { void* data_end = (void*)(long)ctx->data_end; void* data = (void*)(long)ctx->data; struct ethhdr* eth = data; uint64_t nh_off = sizeof(*eth); if (data + nh_off > data_end) { return XDP_PASS; } uint16_t h_proto = eth->h_proto; if (h_proto == htons(ETH_P_IP)) { struct iphdr* iph = data + nh_off; struct tcphdr* tcph = data + nh_off + sizeof(struct iphdr); if (tcph + 1 > (struct tcphdr*)data_end) { return XDP_PASS; } if (iph->protocol == IPPROTO_TCP && tcph->dest == htons(1234)){ iph->saddr = iph->daddr; iph->daddr = 4266428307; bpf_debug("Received!\n"); uint8_t swap_eth[ETH_ALEN]; memcpy(swap_eth, eth->h_dest, ETH_ALEN); memcpy(eth->h_dest, eth->h_source, ETH_ALEN); memcpy(eth->h_source, swap_eth, ETH_ALEN); return XDP_TX; } } return XDP_PASS; } char _license[] SEC("license") = "GPL";
Strangely I'm not receiving TCP packets on my destination server *(147.135.76.254 | 4266428307), and also on the local server the packet doesn't appear in tcpdump -i eth0 dst port 1234
Am I doing something wrong? If yes, how can I fix the code.
The purpose is: Receive packet on server port LOCAL:1234, and redirect to DESTINATION:1234
Updates:
The program seems to work correctly, I'm getting the message "Received!" in cat /sys/kernel/debug/tracing/trace_pipe
The packet did not reach the destination server
In the destination server (Windows), i'm running Wireshark with TCP Checksum verification disabled, example:
On source server (linux), i send hping3 147.135.76.254 -p 65534 -- badcksum and receive all packets in wireshark (dest server)
In source server (XDP), when i execute: tcpdump -i eth0 tcp port 1234, i'm not receiving any packets.
Note: I used ethtool -K eth0 tx off to disable offload / chksum
If i change XDP_TX to XDP_PASS i can receive this packet in tcpdump (command above):
14:38:10.964195 IP d2-2-us-east-va-1.39698 > 147.135.76.254.65534: Flags [S], seq 3962643128, win 14600, options [mss 1460,sackOK,TS val 2414158903 ecr 0,nop,wscale 9], length 0In ethtool -S eth0 shows rx/tx correctly
-
Need help in XDP program failing to load with error "R4 min value is negative, either use unsigned or 'var &= const'"
I have written a XDP program that looks at the incoming TCP packets.
Basically I'm exchanging the destination IPv4 address to another server on the same network
Observation: If I put a fixed value in the function instead of the tcp_len variable the problem goes away, or if I add the following check:
if(tcp_len > 20){ return XDP_PASS; }
the error also disappears
I need to fix this problem, I believe the error is related to my function to calculate the checksum or some other detail that I'm missing
Following is the code:
// SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) // Copyright (c) 2018 Netronome Systems, Inc. #define BPF_NO_GLOBAL_DATA #define MAX_PACKET_OFF 0xffff #include <stdbool.h> #include <stddef.h> #include <string.h> #include <linux/bpf.h> #include <linux/icmp.h> #include <linux/if_ether.h> #include <linux/if_vlan.h> #include <linux/in.h> #include <linux/ip.h> #include <linux/tcp.h> #include <linux/udp.h> #include <linux/ipv6.h> #include "bpf_endian.h" #include "bpf_helpers.h" #include "jhash.h" #include <stdint.h> #define htons(x) ((__be16)___constant_swab16((x))) #define htonl(x) ((__be32)___constant_swab32((x))) __attribute__((__always_inline__)) static inline __u16 csum_fold_helper(__u64 csum) { int i; #pragma unroll for (i = 0; i < 4; i++) { if (csum >> 16) csum = (csum & 0xffff) + (csum >> 16); } return ~csum; } __attribute__((__always_inline__)) static inline void ipv4_csum(void* data_start, int data_size, __u64* csum) { *csum = bpf_csum_diff(0, 0, data_start, data_size, *csum); *csum = csum_fold_helper(*csum); } __attribute__((__always_inline__)) static inline void ipv4_l4_csum(void* data_start, __u32 data_size, __u64* csum, struct iphdr* iph) { __u32 tmp = 0; *csum = bpf_csum_diff(0, 0, &iph->saddr, sizeof(__be32), *csum); *csum = bpf_csum_diff(0, 0, &iph->daddr, sizeof(__be32), *csum); tmp = __builtin_bswap32((__u32)(iph->protocol)); *csum = bpf_csum_diff(0, 0, &tmp, sizeof(__u32), *csum); tmp = __builtin_bswap32((__u32)(data_size)); *csum = bpf_csum_diff(0, 0, &tmp, sizeof(__u32), *csum); *csum = bpf_csum_diff(0, 0, data_start, data_size, *csum); *csum = csum_fold_helper(*csum); } SEC("prog") int xdp_drop_benchmark_traffic(struct xdp_md* ctx) { void* data_end = (void*)(long)ctx->data_end; void* data = (void*)(long)ctx->data; struct ethhdr* eth = data; uint64_t nh_off = sizeof(*eth); if (data + nh_off > data_end) { return XDP_PASS; } uint16_t h_proto = eth->h_proto; if (h_proto == htons(ETH_P_IP)) { struct iphdr* iph = data + nh_off; struct tcphdr* tcph = data + nh_off + sizeof(struct iphdr); if (tcph + 1 > (struct tcphdr*)data_end || iph->protocol != IPPROTO_TCP){ return XDP_PASS; } __u16 tcp_len = htons(iph->tot_len) - (iph->ihl << 2); if (tcp_len > MAX_PACKET_OFF) { return XDP_DROP; } if (tcph->dest == htons(1234)) { iph->saddr = iph->daddr; iph->daddr = 4266428307; __u64 csum = 0; iph->check = 0; ipv4_csum(iph, sizeof(struct iphdr), &csum); iph->check = csum; csum = 0; tcph->check = 0; bpf_debug("TCP Len: %i | %i\n", tcp_len, htonl(tcp_len)); ipv4_l4_csum(tcph, tcp_len, &csum, iph); tcph->check = csum; return XDP_TX; } } return XDP_PASS; } char _license[] SEC("license") = "GPL";
The log:
libbpf: loading main.o libbpf: elf: section(3) prog, size 1096, link 0, flags 6, type=1 libbpf: sec 'prog': found program 'xdp_drop_benchmark_traffic' at insn offset 0 (0 bytes), code size 137 insns (1096 bytes) libbpf: elf: section(4) .rodata.str1.16, size 18, link 0, flags 32, type=1 libbpf: elf: skipping unrecognized data section(4) .rodata.str1.16 libbpf: elf: section(5) license, size 4, link 0, flags 3, type=1 libbpf: license of main.o is GPL libbpf: elf: section(6) .eh_frame, size 48, link 0, flags 2, type=1 libbpf: elf: skipping unrecognized data section(6) .eh_frame libbpf: elf: section(7) .rel.eh_frame, size 16, link 8, flags 0, type=9 libbpf: elf: skipping relo section(7) .rel.eh_frame for section(6) .eh_frame libbpf: elf: section(8) .symtab, size 288, link 1, flags 0, type=2 libbpf: looking for externs among 12 symbols... libbpf: collected 0 externs total libbpf: prog 'xdp_drop_benchmark_traffic': unrecognized ELF section name 'prog' libbpf: load bpf program failed: Permission denied libbpf: -- BEGIN DUMP LOG --- libbpf: 0: (b7) r0 = 2 1: (61) r2 = *(u32 *)(r1 +4) 2: (61) r7 = *(u32 *)(r1 +0) 3: (bf) r3 = r7 4: (07) r3 += 14 5: (2d) if r3 > r2 goto pc+130 R0_w=inv2 R1=ctx(id=0,off=0,imm=0) R2_w=pkt_end(id=0,off=0,imm=0) R3_w=pkt(id=0,off=14,r=14,imm=0) R7_w=pkt(id=0,off=0,r=14,imm=0) R10=fp0 6: (71) r1 = *(u8 *)(r7 +12) 7: (71) r4 = *(u8 *)(r7 +13) 8: (67) r4 <<= 8 9: (4f) r4 |= r1 10: (55) if r4 != 0x8 goto pc+125 R0_w=inv2 R1_w=inv(id=0,umax_value=255,var_off=(0x0; 0xff)) R2_w=pkt_end(id=0,off=0,imm=0) R3_w=pkt(id=0,off=14,r=14,imm=0) R4_w=inv8 R7_w=pkt(id=0,off=0,r=14,imm=0) R10=fp0 11: (bf) r1 = r7 12: (07) r1 += 54 13: (2d) if r1 > r2 goto pc+122 R0=inv2 R1=pkt(id=0,off=54,r=54,imm=0) R2=pkt_end(id=0,off=0,imm=0) R3=pkt(id=0,off=14,r=54,imm=0) R4=inv8 R7=pkt(id=0,off=0,r=54,imm=0) R10=fp0 14: (71) r1 = *(u8 *)(r7 +23) 15: (55) if r1 != 0x6 goto pc+120 R0=inv2 R1_w=inv6 R2=pkt_end(id=0,off=0,imm=0) R3=pkt(id=0,off=14,r=54,imm=0) R4=inv8 R7=pkt(id=0,off=0,r=54,imm=0) R10=fp0 16: (69) r1 = *(u16 *)(r7 +36) 17: (55) if r1 != 0xd204 goto pc+118 R0=inv2 R1_w=inv53764 R2=pkt_end(id=0,off=0,imm=0) R3=pkt(id=0,off=14,r=54,imm=0) R4=inv8 R7=pkt(id=0,off=0,r=54,imm=0) R10=fp0 18: (69) r6 = *(u16 *)(r7 +16) 19: (dc) r6 = be16 r6 20: (71) r9 = *(u8 *)(r7 +14) 21: (67) r9 <<= 2 22: (57) r9 &= 60 23: (61) r1 = *(u32 *)(r7 +30) 24: (18) r2 = 0xfe4c8793 26: (63) *(u32 *)(r7 +30) = r2 27: (63) *(u32 *)(r7 +26) = r1 28: (b7) r8 = 0 29: (6b) *(u16 *)(r7 +24) = r8 30: (b7) r1 = 0 31: (b7) r2 = 0 32: (b7) r4 = 20 33: (b7) r5 = 0 34: (85) call bpf_csum_diff#28 last_idx 34 first_idx 13 regs=4 stack=0 before 33: (b7) r5 = 0 regs=4 stack=0 before 32: (b7) r4 = 20 regs=4 stack=0 before 31: (b7) r2 = 0 last_idx 34 first_idx 13 regs=10 stack=0 before 33: (b7) r5 = 0 regs=10 stack=0 before 32: (b7) r4 = 20 35: (bf) r1 = r0 36: (77) r1 >>= 16 37: (15) if r1 == 0x0 goto pc+2 R0=inv(id=0) R1_w=inv(id=0,umax_value=281474976710655,var_off=(0x0; 0xffffffffffff)) R6=inv(id=0) R7=pkt(id=0,off=0,r=54,imm=0) R8=inv0 R9=inv(id=0,umax_value=60,var_off=(0x0; 0x3c)) R10=fp0 38: (57) r0 &= 65535 39: (0f) r0 += r1 40: (1f) r6 -= r9 41: (bf) r1 = r0 42: (77) r1 >>= 16 43: (15) if r1 == 0x0 goto pc+2 R0_w=inv(id=0,umax_value=281474976776190,var_off=(0x0; 0x1ffffffffffff)) R1_w=inv(id=0,umax_value=4294967296,var_off=(0x0; 0x1ffffffff)) R6_w=inv(id=0) R7=pkt(id=0,off=0,r=54,imm=0) R8=inv0 R9=inv(id=0,umax_value=60,var_off=(0x0; 0x3c)) R10=fp0 44: (57) r0 &= 65535 45: (0f) r0 += r1 46: (bf) r1 = r7 47: (07) r1 += 34 48: (7b) *(u64 *)(r10 -40) = r1 49: (57) r6 &= 65535 50: (bf) r1 = r0 51: (77) r1 >>= 16 52: (15) if r1 == 0x0 goto pc+2 R0=inv(id=0,umax_value=4295032831,var_off=(0x0; 0x1ffffffff)) R1_w=inv(id=0,umax_value=65536,var_off=(0x0; 0x1ffff)) R6_w=inv(id=0,umax_value=65535,var_off=(0x0; 0xffff)) R7=pkt(id=0,off=0,r=54,imm=0) R8=inv0 R9=inv(id=0,umax_value=60,var_off=(0x0; 0x3c)) R10=fp0 fp-40_w=pkt 53: (57) r0 &= 65535 54: (0f) r0 += r1 55: (bf) r1 = r0 56: (77) r1 >>= 16 57: (0f) r1 += r0 58: (a7) r1 ^= -1 59: (6b) *(u16 *)(r7 +24) = r1 60: (6b) *(u16 *)(r7 +50) = r8 61: (b7) r1 = 10 62: (6b) *(u16 *)(r10 -16) = r1 63: (18) r1 = 0x6925207c20692520 65: (7b) *(u64 *)(r10 -24) = r1 66: (18) r1 = 0x3a6e654c20504354 68: (7b) *(u64 *)(r10 -32) = r1 69: (bf) r8 = r6 70: (dc) r8 = be32 r8 71: (bf) r1 = r10 72: (07) r1 += -32 73: (b7) r2 = 18 74: (bf) r3 = r6 75: (bf) r4 = r8 76: (85) call bpf_trace_printk#6 last_idx 76 first_idx 46 regs=4 stack=0 before 75: (bf) r4 = r8 regs=4 stack=0 before 74: (bf) r3 = r6 regs=4 stack=0 before 73: (b7) r2 = 18 77: (bf) r3 = r7 78: (07) r3 += 26 79: (b7) r1 = 0 80: (b7) r2 = 0 81: (b7) r4 = 4 82: (b7) r5 = 0 83: (85) call bpf_csum_diff#28 last_idx 83 first_idx 77 regs=4 stack=0 before 82: (b7) r5 = 0 regs=4 stack=0 before 81: (b7) r4 = 4 regs=4 stack=0 before 80: (b7) r2 = 0 last_idx 83 first_idx 77 regs=10 stack=0 before 82: (b7) r5 = 0 regs=10 stack=0 before 81: (b7) r4 = 4 84: (bf) r3 = r7 85: (07) r3 += 30 86: (b7) r1 = 0 87: (b7) r2 = 0 88: (b7) r4 = 4 89: (bf) r5 = r0 90: (85) call bpf_csum_diff#28 last_idx 90 first_idx 77 regs=4 stack=0 before 89: (bf) r5 = r0 regs=4 stack=0 before 88: (b7) r4 = 4 regs=4 stack=0 before 87: (b7) r2 = 0 last_idx 90 first_idx 77 regs=10 stack=0 before 89: (bf) r5 = r0 regs=10 stack=0 before 88: (b7) r4 = 4 91: (71) r1 = *(u8 *)(r7 +23) 92: (dc) r1 = be32 r1 93: (63) *(u32 *)(r10 -32) = r1 94: (bf) r9 = r10 95: (07) r9 += -32 96: (b7) r1 = 0 97: (b7) r2 = 0 98: (bf) r3 = r9 99: (b7) r4 = 4 100: (bf) r5 = r0 101: (85) call bpf_csum_diff#28 last_idx 101 first_idx 91 regs=4 stack=0 before 100: (bf) r5 = r0 regs=4 stack=0 before 99: (b7) r4 = 4 regs=4 stack=0 before 98: (bf) r3 = r9 regs=4 stack=0 before 97: (b7) r2 = 0 last_idx 101 first_idx 91 regs=10 stack=0 before 100: (bf) r5 = r0 regs=10 stack=0 before 99: (b7) r4 = 4 102: (63) *(u32 *)(r10 -32) = r8 103: (b7) r1 = 0 104: (b7) r2 = 0 105: (bf) r3 = r9 106: (b7) r4 = 4 107: (bf) r5 = r0 108: (85) call bpf_csum_diff#28 last_idx 108 first_idx 91 regs=4 stack=0 before 107: (bf) r5 = r0 regs=4 stack=0 before 106: (b7) r4 = 4 regs=4 stack=0 before 105: (bf) r3 = r9 regs=4 stack=0 before 104: (b7) r2 = 0 last_idx 108 first_idx 91 regs=10 stack=0 before 107: (bf) r5 = r0 regs=10 stack=0 before 106: (b7) r4 = 4 109: (b7) r1 = 0 110: (b7) r2 = 0 111: (79) r3 = *(u64 *)(r10 -40) 112: (bf) r4 = r6 113: (bf) r5 = r0 114: (85) call bpf_csum_diff#28 last_idx 114 first_idx 109 regs=4 stack=0 before 113: (bf) r5 = r0 regs=4 stack=0 before 112: (bf) r4 = r6 regs=4 stack=0 before 111: (79) r3 = *(u64 *)(r10 -40) regs=4 stack=0 before 110: (b7) r2 = 0 invalid access to packet, off=34 size=65535, R3(id=0,off=34,r=54) R3 offset is outside of the packet processed 112 insns (limit 1000000) max_states_per_insn 0 total_states 6 peak_states 6 mark_read 3 libbpf: -- END LOG -- libbpf: failed to load program 'xdp_drop_benchmark_traffic' libbpf: failed to load object 'main.o' Error fetching program/map!
I would like to understand where I am going wrong, and what is the correct source code.
Thanks