Commit 5a937ca2 authored by Joanne Hugé's avatar Joanne Hugé

Add AF_XDP test program

parent 7f143fbf
...@@ -2,3 +2,9 @@ ecpri-tests/client ...@@ -2,3 +2,9 @@ ecpri-tests/client
ecpri-tests/server ecpri-tests/server
*.swp *.swp
*.swo *.swo
af-xdp/xdp_kern.ll
af-xdp/xdp_kern.o
af-xdp/xdp_user
af-xdp/xdp_user.d
af-xdp/xdp_user.o
USER = xdp_user
KERN = xdp_kern
LIBBPF = ${HOME}/xdp/libbpf-build/usr
SRCDIR = "."
SRCS = $(USER).c
OBJS = $(SRCS:%.c=%.o)
ifeq ($(DEBUG),)
CFLAGS = -O2
else
CFLAGS = -Og -g -Wall -Wextra
endif
CFLAGS += -MD -MP
CFLAGS += -I $(SRCDIR)
CFLAGS += -std=gnu99
LDFLAGS += -pthread -L$(LIBBPF)/lib64 -l:libbpf.a -lelf -lz
CFLAGS += -I $(LIBBPF)/include
vpath %.c $(SRCDIR)
$(USER): $(OBJS) xdp_kern.o
$(CC) $(CFLAGS) $(OBJS) $(LDFLAGS) -o $@
xdp_kern.o: $(KERN).c
clang $(IFLAGS) -isystem $(LIBBPF)/include -S -target bpf -D __BPF_TRACING__ -Wall -O2 -emit-llvm -c -g -o $(KERN).ll $^
llc -march=bpf -filetype=obj -o $@ $(KERN).ll
-include $(subst .c,.d,$(SRCS))
clean:
$(RM) -rf bin
$(RM) $(OBJS) $(USER) $(subst .c,.d,$(SRCS))
$(RM) -rf xdp_kern.o $(KERN).ll
.PHONY: clean
#define KBUILD_MODNAME "blub"
#include <linux/bpf.h>
#include <linux/if_ether.h>
#include <linux/if_link.h>
#include <linux/if_xdp.h>
#include <linux/in.h>
#include <linux/ip.h>
#include <linux/udp.h>
//#include "/root/xdp/libbpf-build/usr/include/bpf/bpf_helpers.h"
//#include "/root/xdp/libbpf-build/usr/include/bpf/bpf_endian.h"
#include "bpf/bpf_helpers.h"
#include "bpf/bpf_endian.h"
//#include <bpf/bpf_helpers.h>
//#include <bpf/bpf_endian.h>
struct bpf_map_def SEC("maps") xsks_map = {
.type = BPF_MAP_TYPE_XSKMAP,
.key_size = sizeof(int),
.value_size = sizeof(int),
.max_entries = 64,
};
SEC("xdp_sock")
int xdp_sock_prog(struct xdp_md *ctx)
{
int index;
index = ctx->rx_queue_index;
/* If socket bound to rx_queue then redirect to user space */
if (bpf_map_lookup_elem(&xsks_map, &index))
return bpf_redirect_map(&xsks_map, index, 0);
/* Else pass to Linux' network stack */
return XDP_PASS;
}
char _license[] SEC("license") = "GPL";
#define _GNU_SOURCE
#include <arpa/inet.h>
#include <errno.h>
#include <error.h>
#include <fcntl.h>
#include <getopt.h>
#include <ifaddrs.h>
#include <inttypes.h>
#include <limits.h>
#include <linux/errqueue.h>
#include <linux/ethtool.h>
#include <linux/net_tstamp.h>
#include <linux/sockios.h>
#include <net/if.h>
#include <netdb.h>
#include <netinet/in.h>
#include <poll.h>
#include <pthread.h>
#include <sched.h>
#include <signal.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
#include <bpf/bpf.h>
#include <bpf/libbpf.h>
#include <bpf/xsk.h>
#include <linux/if_ether.h>
#include <linux/if_link.h>
#include <linux/if_xdp.h>
#include <linux/ip.h>
#include <linux/udp.h>
#define err(...) \
do { \
fprintf(stderr, __VA_ARGS__); \
exit(EXIT_FAILURE); \
} while (0)
#define err_errno(...) error(EXIT_FAILURE, errno, __VA_ARGS__);
#define NUM_FRAMES 4096
#define ETH_FCS_SIZE 4
#define FRAME_SIZE XSK_UMEM__DEFAULT_FRAME_SIZE
#define PACKET_SIZE 64
#define DEBUG
static void log_info(const char * section, const char * msg, ...) {
time_t t;
struct tm ts;
char line[256];
va_list arglist;
time(&t);
ts = *localtime(&t);
strftime(line, 80, "%m-%d %H:%M:%S", &ts);
sprintf(line + strlen(line), " INFO [%s] ", section);
va_start(arglist, msg);
vsprintf(line + strlen(line), msg, arglist);
va_end(arglist);
puts(line);
}
#ifdef DEBUG
static void log_debug(const char * section, const char * msg, ...) {
time_t t;
struct tm ts;
char line[256];
va_list arglist;
time(&t);
ts = *localtime(&t);
strftime(line, 80, "%m-%d %H:%M:%S", &ts);
sprintf(line + strlen(line), " DEBUG [%s] ", section);
va_start(arglist, msg);
vsprintf(line + strlen(line), msg, arglist);
va_end(arglist);
puts(line);
}
#else
#define log_debug(...)
#endif
struct xsk_umem_info {
struct xsk_ring_prod fq;
struct xsk_ring_cons cq;
struct xsk_umem *umem;
void *buffer;
};
struct xdpsock {
struct xsk_ring_cons rx;
struct xsk_ring_prod tx;
struct xsk_umem_info umem;
struct xsk_socket *xsk;
int fd;
};
static void init_xdp_recv(char * network_if);
static void init_xdp_send(char * network_if);
static int recv_xdp_packet(void);
static void init_recv(void);
static void send_xdp_packet(void);
static void recv_xdp_cleanup(void);
static void close_xdp_socket(void);
static uint8_t pkt_data[XSK_UMEM__DEFAULT_FRAME_SIZE];
static struct xdpsock send_xdp_socket;
static struct xdpsock recv_xdp_socket;
static int received;
static uint32_t idx_rx = 0, idx_recv;
int main() {
char * network_if = "ens9f1np1";
log_info("", "Starting");
init_xdp_send(network_if);
//init_xdp_recv(network_if);
return 0;
}
static void init_xdp_send(char * network_if) {
uint32_t idx;
int ret, i, xsks_map = 0;
int batch_size;
struct xsk_socket_config xsk_cfg;
struct xsk_umem_config cfg = {
.fill_size = XSK_RING_PROD__DEFAULT_NUM_DESCS,
.comp_size = XSK_RING_CONS__DEFAULT_NUM_DESCS,
.frame_size = FRAME_SIZE,
.frame_headroom = XSK_UMEM__DEFAULT_FRAME_HEADROOM,
.flags = 0,
};
void *buffer = NULL;
struct ethhdr *eth_hdr = (struct ethhdr *)pkt_data;
memcpy(eth_hdr->h_dest, "\xb8\x59\x9f\x07\x7d\xdb", ETH_ALEN);
memcpy(eth_hdr->h_source, "\x04\x09\xa5\x0f\x9f\x4c", ETH_ALEN);
eth_hdr->h_proto = htons(ETH_P_IP);
log_debug("", "posix_memalign");
/* Allocate user space memory for xdp frames */
ret = posix_memalign(&buffer, sysconf(_SC_PAGE_SIZE), NUM_FRAMES * FRAME_SIZE);
if (ret) err_errno("posix_memalign() failed");
log_debug("", "xsk_umem__create");
ret = xsk_umem__create(&send_xdp_socket.umem.umem, buffer, NUM_FRAMES * FRAME_SIZE,
&send_xdp_socket.umem.fq, &send_xdp_socket.umem.cq, &cfg);
if (ret) err("xsk_umem__create() failed");
send_xdp_socket.umem.buffer = buffer;
log_debug("", "open_xdp_socket");
/* Create XDP socket */
xsk_cfg.rx_size = XSK_RING_CONS__DEFAULT_NUM_DESCS;
xsk_cfg.tx_size = XSK_RING_PROD__DEFAULT_NUM_DESCS;
xsk_cfg.libbpf_flags = 0;
xsk_cfg.xdp_flags = XDP_FLAGS_DRV_MODE;
xsk_cfg.bind_flags = 0;
log_debug("", "xsk_socket__create");
ret = xsk_socket__create(&send_xdp_socket.xsk, network_if, 0, send_xdp_socket.umem.umem,
&send_xdp_socket.rx, &send_xdp_socket.tx, &xsk_cfg);
log_debug("", "send_xdp_packet");
send_xdp_packet();
}
static void init_xdp_recv(char * network_if) {
uint32_t idx;
int ret, i, xsks_map = 0;
int batch_size;
struct xsk_socket_config xsk_cfg;
struct xsk_umem_config cfg = {
.fill_size = XSK_RING_PROD__DEFAULT_NUM_DESCS,
.comp_size = XSK_RING_CONS__DEFAULT_NUM_DESCS,
.frame_size = FRAME_SIZE,
.frame_headroom = XSK_UMEM__DEFAULT_FRAME_HEADROOM,
.flags = 0,
};
void *buffer = NULL;
log_debug("", "posix_memalign");
/* Allocate user space memory for xdp frames */
ret = posix_memalign(&buffer, sysconf(_SC_PAGE_SIZE), NUM_FRAMES * FRAME_SIZE);
if (ret) err_errno("posix_memalign() failed");
log_debug("", "xsk_umem__create");
ret = xsk_umem__create(&recv_xdp_socket.umem.umem, buffer, NUM_FRAMES * FRAME_SIZE,
&recv_xdp_socket.umem.fq, &recv_xdp_socket.umem.cq, &cfg);
if (ret) err("xsk_umem__create() failed");
recv_xdp_socket.umem.buffer = buffer;
log_debug("", "open_xdp_socket");
/* Create XDP socket */
xsk_cfg.rx_size = XSK_RING_CONS__DEFAULT_NUM_DESCS;
xsk_cfg.tx_size = XSK_RING_PROD__DEFAULT_NUM_DESCS;
xsk_cfg.libbpf_flags = 0;
xsk_cfg.xdp_flags = XDP_FLAGS_DRV_MODE;
xsk_cfg.bind_flags = 0;
log_debug("", "xsk_socket__create");
ret = xsk_socket__create(&recv_xdp_socket.xsk, network_if, 0, recv_xdp_socket.umem.umem,
&recv_xdp_socket.rx, &recv_xdp_socket.tx, &xsk_cfg);
log_debug("", "recv_xdp_packet");
recv_xdp_packet();
}
static void send_xdp_packet(void) {
struct pollfd fds[1] = {};
int i, ret;
fds[0].fd = xsk_socket__fd(send_xdp_socket.xsk);
fds[0].events = POLLOUT;
for (int i = 0; i < NUM_FRAMES; i++)
memcpy(xsk_umem__get_data(send_xdp_socket.umem.buffer, i * XSK_UMEM__DEFAULT_FRAME_SIZE), pkt_data, PACKET_SIZE - ETH_FCS_SIZE);
while(1) {
int batch_size = 64;
uint32_t idx;
log_debug("", "polling");
ret = poll(fds, 1, -1);
if ((ret <= 0) || !(fds[0].revents & POLLOUT))
continue;
log_debug("", "reserve");
xsk_ring_prod__reserve(&send_xdp_socket.tx, batch_size, &idx);
for (int k = 0; k < batch_size; k++) {
struct xdp_desc *tx_desc = xsk_ring_prod__tx_desc(&send_xdp_socket.tx, idx + k);
tx_desc->addr = k * (PACKET_SIZE);
tx_desc->len = PACKET_SIZE - ETH_FCS_SIZE;
}
log_debug("", "submit");
xsk_ring_prod__submit(&send_xdp_socket.tx, batch_size);
log_debug("", "submit done");
break;
}
}
static int recv_xdp_packet(void) {
int ret;
static struct pollfd fds_recv[1] = {0};
fds_recv[0].fd = xsk_socket__fd(recv_xdp_socket.xsk);
fds_recv[0].events = POLLIN;
/* Add some buffers in fill ring */
log_debug("", "xsk_ring_prod__reserve");
ret = xsk_ring_prod__reserve(&recv_xdp_socket.umem.fq,
XSK_RING_PROD__DEFAULT_NUM_DESCS, &idx_recv);
if (ret != XSK_RING_PROD__DEFAULT_NUM_DESCS)
err("xsk_ring_prod__reserve() failed");
log_debug("", "xsk_ring_prod__fill_addr");
for (int i = 0; i < XSK_RING_PROD__DEFAULT_NUM_DESCS; i++)
*xsk_ring_prod__fill_addr(&recv_xdp_socket.umem.fq, idx_recv++) = i * FRAME_SIZE;
log_debug("", "xsk_ring_prod__submit");
xsk_ring_prod__submit(&recv_xdp_socket.umem.fq, XSK_RING_PROD__DEFAULT_NUM_DESCS);
ret = poll(fds_recv, 1, -1);
if (ret != 1)
error(EXIT_FAILURE, errno, "poll failed");
log_info("", "xsk_ring_cons__peek");
received = xsk_ring_cons__peek(&recv_xdp_socket.rx, 1, &idx_rx);
log_info("", "Received packet ! (%d)", received);
if (received != 1)
error(EXIT_FAILURE, errno, "Received %d packets", received);
return 0;
}
static void recv_xdp_cleanup(void) {
uint64_t addr;
int ret;
/* Cleanup */
xsk_ring_cons__release(&recv_xdp_socket.rx, received);
/* Add that particular buffer back to the fill queue */
if (xsk_prod_nb_free(&recv_xdp_socket.umem.fq, received)) {
ret = xsk_ring_prod__reserve(&recv_xdp_socket.umem.fq, received, &idx_recv);
if (ret != received) err("xsk_ring_prod__reserve() failed");
*xsk_ring_prod__fill_addr(&recv_xdp_socket.umem.fq, idx_recv) =
xsk_umem__extract_addr(addr);
xsk_ring_prod__submit(&recv_xdp_socket.umem.fq, received);
}
}
static void close_xdp_socket(void) {
xsk_socket__delete(send_xdp_socket.xsk);
xsk_socket__delete(recv_xdp_socket.xsk);
xsk_umem__delete(send_xdp_socket.umem.umem);
xsk_umem__delete(recv_xdp_socket.umem.umem);
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment