Commit 126217da authored by Joanne Hugé's avatar Joanne Hugé

Add AF_XDP sockets

Describe XDP option in help
Add option to link with local libbpf folder
Update wrapper server script
Fix min max functions conflicts
Compile xdp-kern.o
Add IFLAGS to CFLAGS in makefile for XDP
Add bpf_helpers and xdp_kern files
Close XDP socket before exiting program
Add tracecmd option for XDP
Print stats for XDP too
Add an active polling mode
parent 682b8420
...@@ -27,15 +27,35 @@ CFLAGS += -MD -MP ...@@ -27,15 +27,35 @@ CFLAGS += -MD -MP
CFLAGS += -I $(SRCDIR) CFLAGS += -I $(SRCDIR)
CFLAGS += -std=gnu99 CFLAGS += -std=gnu99
LDFLAGS = -pthread LLIBS = -pthread
ifneq ($(WITH_XDP),)
CFLAGS += -D WITH_XDP
LDFLAGS += -L/usr/lib -lbpf
else ifneq ($(WITH_GIT_XDP),)
IFLAGS += -I ${HOME}/libbpf/include
CFLAGS += -D WITH_XDP $(IFLAGS)
LDIRS += -L${HOME}/libbpf/src
LLIBS += -lelf -lz -l:libbpf.a
endif
vpath %.c $(SRCDIR) vpath %.c $(SRCDIR)
xdp_kern.o: xdp_kern.c
clang $(IFLAGS) -isystem /usr/include/arm-linux-gnueabihf -S -target bpf -D __BPF_TRACING__ -Wall -O2 -emit-llvm -c -g -o xdp_kern.ll $^
llc -march=bpf -filetype=obj -o $@ xdp_kern.ll
ifneq ($(WITH_GIT_XDP),)
$(SERVER_PROG): $(SERVER_OBJS) xdp_kern.o
$(CC) $(LDFLAGS) $(LDIRS) $(SERVER_OBJS) $(LLIBS) -o $@
else
$(SERVER_PROG): $(SERVER_OBJS) $(SERVER_PROG): $(SERVER_OBJS)
$(CC) $(LDFLAGS) $^ -o $@ $(CC) $(LDFLAGS) $(LDIRS) $^ $(LLIBS) -o $@
endif
$(CLIENT_PROG): $(CLIENT_OBJS) $(CLIENT_PROG): $(CLIENT_OBJS)
$(CC) $(LDFLAGS) $^ -o $@ $(CC) $(LDFLAGS) $(LDIRS) $^ $(LLIBS) -o $@
-include $(subst .c,.d,$(SERVER_SRCS)) -include $(subst .c,.d,$(SERVER_SRCS))
-include $(subst .c,.d,$(CLIENT_SRCS)) -include $(subst .c,.d,$(CLIENT_SRCS))
......
This diff is collapsed.
This diff is collapsed.
#define _GNU_SOURCE #define _GNU_SOURCE
#include "common.h"
#include <inttypes.h> #include <inttypes.h>
#include <signal.h> #include <signal.h>
#include <stdint.h> #include <stdint.h>
...@@ -7,73 +9,65 @@ ...@@ -7,73 +9,65 @@
#include <time.h> #include <time.h>
#include <unistd.h> #include <unistd.h>
#include "common.h"
void (*previous_handlers[NSIG])(int); void (*previous_handlers[NSIG])(int);
static void (*sighand)(int); static void (*sighand)(int);
uint64_t ts_to_uint(struct timespec t) { uint64_t ts_to_uint(struct timespec t) {
return t.tv_sec * NSEC_PER_SEC + t.tv_nsec; return t.tv_sec * NSEC_PER_SEC + t.tv_nsec;
} }
void add_ns(struct timespec *t, uint64_t ns) { void add_ns(struct timespec *t, uint64_t ns) {
t->tv_nsec += ns; t->tv_nsec += ns;
while ((unsigned int)t->tv_nsec >= NSEC_PER_SEC) { while ((unsigned int)t->tv_nsec >= NSEC_PER_SEC) {
t->tv_sec += 1; t->tv_sec += 1;
t->tv_nsec -= NSEC_PER_SEC; t->tv_nsec -= NSEC_PER_SEC;
} }
} }
uint64_t calcdiff_ns(struct timespec t1, struct timespec t2) { uint64_t calcdiff_ns(struct timespec t1, struct timespec t2) {
uint64_t diff; uint64_t diff;
diff = NSEC_PER_SEC * (uint64_t)((int)t1.tv_sec - (int)t2.tv_sec); diff = NSEC_PER_SEC * (uint64_t)((int)t1.tv_sec - (int)t2.tv_sec);
diff += ((int)t1.tv_nsec - (int)t2.tv_nsec); diff += ((int)t1.tv_nsec - (int)t2.tv_nsec);
return diff; return diff;
} }
int max(int a, int b) { return a > b ? a : b; } int _max_(int a, int b) { return a > b ? a : b; }
int min(int a, int b) { return a < b ? a : b; } int _min_(int a, int b) { return a < b ? a : b; }
int histogram_min(uint64_t * histogram, int max_value) { int histogram_min(uint64_t *histogram, int max_value) {
int ret = max_value; int ret = max_value;
for (int i = max_value; i >= 0; i--) for (int i = max_value; i >= 0; i--) ret = histogram[i] ? i : ret;
ret = histogram[i] ? i : ret; return ret;
return ret;
} }
int histogram_max(uint64_t * histogram, int max_value) { int histogram_max(uint64_t *histogram, int max_value) {
int ret = 0; int ret = 0;
for (int i = 0; i <= max_value; i++) for (int i = 0; i <= max_value; i++) ret = histogram[i] ? i : ret;
ret = histogram[i] ? i : ret; return ret;
return ret;
} }
static void sighand_wrapper(int sig) { static void sighand_wrapper(int sig) {
// If we get un unexpected signal, report it, if not print the histogram
// If we get un unexpected signal, report it, if not print the histogram if (sig == SIGINT || sig == SIGTERM)
if (sig == SIGINT || sig == SIGTERM) (*sighand)(sig); // Will print the histogram
(*sighand)(sig); // Will print the histogram else
else printf("Uknown signal interrupt: %s (%d)\n", strsignal(sig),
printf("Uknown signal interrupt: %s (%d)\n", strsignal(sig), sig); sig);
// Execute the default handler // Execute the default handler
if (previous_handlers[sig] == SIG_DFL) { if (previous_handlers[sig] == SIG_DFL) {
signal(sig, SIG_DFL); signal(sig, SIG_DFL);
raise(sig); raise(sig);
} else if (previous_handlers[sig] == SIG_IGN) { } else if (previous_handlers[sig] == SIG_IGN) {
return; return;
} else { } else {
(*previous_handlers[sig])(sig); (*previous_handlers[sig])(sig);
} }
} }
void init_signals(void (*_sighand)(int), int enable_histograms) { void init_signals(void (*_sighand)(int)) {
sighand = _sighand;
sighand = _sighand;
if (enable_histograms) for (int i = 0; i < NSIG; i++) signal(i, sighand_wrapper);
for (int i = 0; i < NSIG; i++)
signal(i, sighand_wrapper);
} }
...@@ -8,6 +8,17 @@ ...@@ -8,6 +8,17 @@
#include <time.h> #include <time.h>
#include <unistd.h> #include <unistd.h>
#ifdef WITH_XDP
#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>
#endif
#define NSEC_PER_SEC UINT64_C(1000000000) #define NSEC_PER_SEC UINT64_C(1000000000)
#define SERVER_PORT "50000" #define SERVER_PORT "50000"
#define SERVER_PORT_INT 50000 #define SERVER_PORT_INT 50000
...@@ -19,18 +30,25 @@ ...@@ -19,18 +30,25 @@
#define MAX_BUFFER_SIZE 1024 #define MAX_BUFFER_SIZE 1024
#define TIMESTAMP_BUFFER_SIZE 4096 #define TIMESTAMP_BUFFER_SIZE 4096
#define err(...) \
do { \
fprintf(stderr, __VA_ARGS__); \
exit(EXIT_FAILURE); \
} while (0)
#define err_errno(...) error(EXIT_FAILURE, errno, __VA_ARGS__);
uint64_t ts_to_uint(struct timespec t); uint64_t ts_to_uint(struct timespec t);
void add_ns(struct timespec *t, uint64_t ns); void add_ns(struct timespec *t, uint64_t ns);
uint64_t calcdiff_ns(struct timespec t1, struct timespec t2); uint64_t calcdiff_ns(struct timespec t1, struct timespec t2);
void init_signals(void (*_sighand)(int), int enable_histograms); void init_signals(void (*_sighand)(int));
int min(int a, int b); int _min_(int a, int b);
int max(int a, int b); int _max_(int a, int b);
int histogram_min(uint64_t * histogram, int max_value); int histogram_min(uint64_t *histogram, int max_value);
int histogram_max(uint64_t * histogram, int max_value); int histogram_max(uint64_t *histogram, int max_value);
extern void (*previous_handlers[NSIG])(int); extern void (*previous_handlers[NSIG])(int);
......
This diff is collapsed.
...@@ -4,37 +4,61 @@ ...@@ -4,37 +4,61 @@
#include "common.h" #include "common.h"
typedef struct ingress_param { typedef struct ingress_param {
char network_if[16]; char network_if[16];
int use_timestamps; int use_timestamps;
int xdp_polling_mode;
int interval;
size_t tx_buffer_len; size_t tx_buffer_len;
} ingress_param_t; } ingress_param_t;
typedef struct ingress_stat { typedef struct ingress_stat {
int min_kernel_latency;
int avg_kernel_latency;
int max_kernel_latency;
int min_kernel_latency; int min_interval;
int avg_kernel_latency; int avg_interval;
int max_kernel_latency; int max_interval;
int min_interval; uint64_t packets_received;
int avg_interval; uint64_t high_kernel_latency;
int max_interval; uint64_t high_jitter;
int lost_packets;
uint64_t packets_received; char data[MAX_BUFFER_SIZE];
uint64_t high_kernel_latency;
uint64_t high_jitter;
int lost_packets;
char data[MAX_BUFFER_SIZE];
} ingress_stat_t; } ingress_stat_t;
void init_udp_recv(ingress_param_t *_params, void init_udp_recv(ingress_param_t *_params, ingress_stat_t *stats,
ingress_stat_t *stats, int use_histogram, uint64_t *_kernel_latency_hist);
int use_histogram,
uint64_t *_kernel_latency_hist); void recv_udp_packet(void);
#ifdef WITH_XDP
#define NUM_FRAMES 4096
#define FRAME_SIZE XSK_UMEM__DEFAULT_FRAME_SIZE
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;
};
#endif
void recv_udp_packet(); void init_xdp_recv(ingress_param_t * _params);
int recv_xdp_packet(void);
void recv_xdp_cleanup(void);
void setup_poll_fd(void);
void close_xdp_socket(void);
#endif #endif
...@@ -222,9 +222,9 @@ static void process_error_queue() { ...@@ -222,9 +222,9 @@ static void process_error_queue() {
ts_buf_read_index = (ts_buf_read_index + 1) % TIMESTAMP_BUFFER_SIZE; ts_buf_read_index = (ts_buf_read_index + 1) % TIMESTAMP_BUFFER_SIZE;
stats->min_kernel_latency = stats->min_kernel_latency =
min(kernel_latency, stats->min_kernel_latency); _min_(kernel_latency, stats->min_kernel_latency);
stats->max_kernel_latency = stats->max_kernel_latency =
max(kernel_latency, stats->max_kernel_latency); _max_(kernel_latency, stats->max_kernel_latency);
stats->avg_kernel_latency = stats->avg_kernel_latency =
(stats->max_kernel_latency * packets_sent + kernel_latency) / (stats->max_kernel_latency * packets_sent + kernel_latency) /
(packets_sent + 1); (packets_sent + 1);
......
This diff is collapsed.
...@@ -75,7 +75,7 @@ static void setkernvar(const char *name, char *value) { ...@@ -75,7 +75,7 @@ static void setkernvar(const char *name, char *value) {
fprintf(stderr, "could not set %s to %s\n", name, value); fprintf(stderr, "could not set %s to %s\n", name, value);
} }
void open_fds() { void open_fds(void) {
fileprefix = debugfileprefix; fileprefix = debugfileprefix;
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
#define TRACER_H #define TRACER_H
void setup_tracer(int enable_graph); void setup_tracer(int enable_graph);
void open_fds(); void open_fds(void);
void tracing(int on); void tracing(int on);
void tracemark(char * s); void tracemark(char * s);
......
#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 "bpf_helpers.h"
#define bpf_printk(fmt, ...) \
({ \
char ____fmt[] = fmt; \
bpf_trace_printk(____fmt, sizeof(____fmt), ##__VA_ARGS__); \
})
struct bpf_map_def SEC("maps") xsks_map = {
.type = BPF_MAP_TYPE_XSKMAP,
.key_size = sizeof(int),
.value_size = sizeof(int),
.max_entries = 64,
};
static inline int parse_ipv4(void *data, unsigned long long nh_off,
void *data_end) {
struct iphdr *iph = data + nh_off;
if ((void *)(iph + 1) > data_end) return 0;
return iph->protocol;
}
SEC("xdp_sock")
int xdp_sock_prog(struct xdp_md *ctx) {
void *data_end = (void *)(long)ctx->data_end;
void *data = (void *)(long)ctx->data;
struct ethhdr *eth = data;
int idx = ctx->rx_queue_index;
unsigned int ipproto = 0;
unsigned long long nh_off;
/* Check if it's a UDP frame: If UDP -> Redirect to active xsk for user
* space. If not -> pass to stack.
*/
nh_off = sizeof(*eth);
if (data + nh_off > data_end) return XDP_PASS;
if (eth->h_proto == __builtin_bswap16(ETH_P_IP))
ipproto = parse_ipv4(data, nh_off, data_end);
if (ipproto != IPPROTO_UDP) return XDP_PASS;
/* If socket bound to rx_queue then redirect to user space */
if (bpf_map_lookup_elem(&xsks_map, &idx))
return bpf_redirect_map(&xsks_map, idx, 0);
/* Else pass to Linux' network stack */
return XDP_PASS;
}
char _license[] SEC("license") = "GPL";
...@@ -3,16 +3,28 @@ ...@@ -3,16 +3,28 @@
script_dir=$(dirname $(realpath $0)) script_dir=$(dirname $(realpath $0))
usage() { usage() {
echo "Usage: $0 [[-bt] [-g INTERVAL]] | (-d NB_PACKETS [-i INTERVAL]) [-T LATENCY_THRESHOLD -G]" 1>&2; echo "Usage: $0 | " 1>&2;
exit 1;
}
usage() {
cat << ENDUSAGE
Usage: $0 SERVER | TCPDUMP [TRACE_OPTS]
SERVER: [-bt] [(-x | -X) POLL] [-g INTERVAL]
TCPDUMP: -d NB_PACKETS [-i INTERVAL]
TRACE_OPTS: (-T LATENCY_THRESHOLD -G) | -E
ENDUSAGE
1>&2;
exit 1; exit 1;
} }
# Default options # Default options
server_options="-a -p 99 -f eth0" server_options="-a -p 99 -f eth0"
make_opts=""
ip="10.100.21." ip="10.100.21."
tcpdump_interval=1000000 tcpdump_interval=1000000
while getopts "b:htd:i:g:T:G" opt; do while getopts "b:htx:X:d:i:g:T:GE" opt; do
case "${opt}" in case "${opt}" in
b ) b )
use_rtt=1 use_rtt=1
...@@ -37,12 +49,23 @@ while getopts "b:htd:i:g:T:G" opt; do ...@@ -37,12 +49,23 @@ while getopts "b:htd:i:g:T:G" opt; do
t ) t )
server_options+=" -t" server_options+=" -t"
;; ;;
x )
server_options+=" -x ${OPTARG}"
make_opts=" -e WITH_XDP=1"
;;
X )
server_options+=" -x ${OPTARG}"
make_opts=" -e WITH_GIT_XDP=1"
;;
T ) T )
server_options+=" -T ${OPTARG}" server_options+=" -T ${OPTARG}"
;; ;;
G ) G )
server_options+=" -G" server_options+=" -G"
;; ;;
E )
enable_xdp_events=1
;;
* ) * )
usage usage
;; ;;
...@@ -78,10 +101,14 @@ if [ -n "${use_tcpdump}" ]; then ...@@ -78,10 +101,14 @@ if [ -n "${use_tcpdump}" ]; then
$script_dir/txtime-stats.py -f server_stats_tmp.out -i $tcpdump_interval; $script_dir/txtime-stats.py -f server_stats_tmp.out -i $tcpdump_interval;
else else
echo "make server"; echo "make $make_opts server";
cd $script_dir/../packet-exchange/build;make server;cd $script_dir cd $script_dir/../packet-exchange/build;make $make_opts server;cd $script_dir
if [ -z "${use_histogram}" ]; then if [ -n "${enable_xdp_events}" ]; then
tracecmd_events="-e irq -e sched -e xdp"
echo "trace-cmd record $tracecmd_events $script_dir/../packet-exchange/build/server $server_options";
trace-cmd record $tracecmd_events $script_dir/../packet-exchange/build/server $server_options;
elif [ -z "${use_histogram}" ]; then
echo "server $server_options"; echo "server $server_options";
$script_dir/../packet-exchange/build/server $server_options; $script_dir/../packet-exchange/build/server $server_options;
else else
......
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