first commit

This commit is contained in:
Rodrigo Bertoldo de Sousa Martins committed 2026-09-13 20:49:33 -03:00
commit 01d7cb1a80
34 files changed
+5723

No files matched your search

+158
View File
@@ -0,0 +1,158 @@
// Exemplo AF_XDP com RX, TX, multi-queue e recycling, sem libbpf/xsk.h
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <net/if.h>
#include <sys/socket.h>
#include <linux/if_xdp.h>
#include <linux/if_ether.h>
#include <sys/mman.h>
#include <poll.h>
#include <stdint.h>
#include <sys/types.h>
#define NUM_FRAMES 4096
#define FRAME_SIZE 2048
#define UMEM_SIZE (NUM_FRAMES * FRAME_SIZE)
#define RX_RING_SIZE 2048
#define TX_RING_SIZE 2048
#define FILL_RING_SIZE 2048
#define COMP_RING_SIZE 2048
#define BATCH_SIZE 64
static inline void die(const char *msg) {
perror(msg);
exit(1);
}
static size_t roundup_page(size_t sz) {
size_t pg = sysconf(_SC_PAGESIZE);
return ((sz + pg - 1) / pg) * pg;
}
// Helpers para acessar os pointers dos rings
#define RING_PROD_PTR(ring) ((volatile __u32 *)(ring))
#define RING_CONS_PTR(ring) ((volatile __u32 *)(ring) + 1)
#define RING_DESC(ring) ((void *)((volatile __u32 *)(ring) + 2))
int main(int argc, char **argv) {
if (argc < 2) {
printf("Uso: %s <iface> [queue_id]\n", argv[0]);
return 1;
}
const char *ifname = argv[1];
int queue_id = 0;
if (argc > 2)
queue_id = atoi(argv[2]);
int ifindex = if_nametoindex(ifname);
if (!ifindex) die("if_nametoindex");
// 1. Crie socket AF_XDP
int xdp_sock = socket(AF_XDP, SOCK_RAW, 0);
if (xdp_sock < 0) die("socket(AF_XDP)");
// 2. Alocar UMEM
void *umem_area = NULL;
if (posix_memalign(&umem_area, getpagesize(), UMEM_SIZE))
die("posix_memalign");
// 3. Registrar UMEM no kernel
struct xdp_umem_reg mr = {
.addr = (__u64)(uintptr_t)umem_area,
.len = UMEM_SIZE,
.chunk_size = FRAME_SIZE,
.headroom = 0,
.flags = 0,
};
if (setsockopt(xdp_sock, SOL_XDP, XDP_UMEM_REG, &mr, sizeof(mr)) < 0)
die("setsockopt(XDP_UMEM_REG)");
// 4. Configurar tamanho dos rings
int sz = FILL_RING_SIZE;
if (setsockopt(xdp_sock, SOL_XDP, XDP_UMEM_FILL_RING, &sz, sizeof(sz)) < 0)
die("setsockopt(XDP_UMEM_FILL_RING)");
sz = COMP_RING_SIZE;
if (setsockopt(xdp_sock, SOL_XDP, XDP_UMEM_COMPLETION_RING, &sz, sizeof(sz)) < 0)
die("setsockopt(XDP_UMEM_COMPLETION_RING)");
sz = RX_RING_SIZE;
if (setsockopt(xdp_sock, SOL_XDP, XDP_RX_RING, &sz, sizeof(sz)) < 0)
die("setsockopt(XDP_RX_RING)");
sz = TX_RING_SIZE;
if (setsockopt(xdp_sock, SOL_XDP, XDP_TX_RING, &sz, sizeof(sz)) < 0)
die("setsockopt(XDP_TX_RING)");
// 5. mmap dos rings (tamanho exato, sem roundup_page)
size_t fill_ring_sz = FILL_RING_SIZE * sizeof(__u64) + 8;
size_t comp_ring_sz = COMP_RING_SIZE * sizeof(__u64) + 8;
size_t rx_ring_sz = RX_RING_SIZE * sizeof(struct xdp_desc) + 8;
size_t tx_ring_sz = TX_RING_SIZE * sizeof(struct xdp_desc) + 8;
void *fill_ring = mmap(NULL, fill_ring_sz, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_POPULATE, xdp_sock, XDP_UMEM_PGOFF_FILL_RING);
if (fill_ring == MAP_FAILED) die("mmap(FILL_RING)");
void *comp_ring = mmap(NULL, comp_ring_sz, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_POPULATE, xdp_sock, XDP_UMEM_PGOFF_COMPLETION_RING);
if (comp_ring == MAP_FAILED) die("mmap(COMP_RING)");
void *rx_ring = mmap(NULL, rx_ring_sz, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_POPULATE, xdp_sock, XDP_PGOFF_RX_RING);
if (rx_ring == MAP_FAILED) die("mmap(RX_RING)");
void *tx_ring = mmap(NULL, tx_ring_sz, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_POPULATE, xdp_sock, XDP_PGOFF_TX_RING);
if (tx_ring == MAP_FAILED) die("mmap(TX_RING)");
printf("fill_ring: %p, comp_ring: %p, rx_ring: %p, tx_ring: %p\n", fill_ring, comp_ring, rx_ring, tx_ring);
// Cheque ponteiros dos rings
printf("fill_prod_ptr: %p, fill_desc: %p\n", RING_PROD_PTR(fill_ring), RING_DESC(fill_ring));
printf("rx_prod_ptr: %p, rx_desc: %p\n", RING_PROD_PTR(rx_ring), RING_DESC(rx_ring));
printf("tx_prod_ptr: %p, tx_desc: %p\n", RING_PROD_PTR(tx_ring), RING_DESC(tx_ring));
printf("comp_prod_ptr: %p, comp_desc: %p\n", RING_PROD_PTR(comp_ring), RING_DESC(comp_ring));
// 6. Preencher fill ring com endereços dos frames
__u64 *fill = (__u64 *)RING_DESC(fill_ring);
for (int i = 0; i < NUM_FRAMES; i++) {
fill[i] = i * FRAME_SIZE;
}
// Atualizar producer pointer do fill ring
*RING_PROD_PTR(fill_ring) = NUM_FRAMES;
// 7. Bind socket AF_XDP à interface/fila
struct sockaddr_xdp sxdp = {
.sxdp_family = AF_XDP,
.sxdp_ifindex = ifindex,
.sxdp_queue_id = queue_id,
.sxdp_flags = 0,
};
if (bind(xdp_sock, (struct sockaddr *)&sxdp, sizeof(sxdp)) < 0)
die("bind(AF_XDP)");
printf("Socket AF_XDP ligado na interface %s (fila %d)\n", ifname, queue_id);
// 8. Poll para pacotes
struct pollfd fds = { .fd = xdp_sock, .events = POLLIN };
struct xdp_desc *rx = (struct xdp_desc *)RING_DESC(rx_ring);
while (1) {
int ret = poll(&fds, 1, 1000);
if (ret < 0) die("poll");
if (ret == 0) continue;
__u32 rx_cons = *RING_CONS_PTR(rx_ring);
__u32 rx_prod = *RING_PROD_PTR(rx_ring);
if (!rx || rx_prod == rx_cons) continue;
while (rx_cons != rx_prod) {
struct xdp_desc *desc = &rx[rx_cons % RX_RING_SIZE];
if (!desc) break;
void *pkt = (char *)umem_area + desc->addr;
printf("Pacote RX: %u bytes (addr=%llu)\n", desc->len, (unsigned long long)desc->addr);
rx_cons++;
}
*RING_CONS_PTR(rx_ring) = rx_cons;
}
// Cleanup (não alcançado neste exemplo)
close(xdp_sock);
free(umem_area);
return 0;
}