Commit e722e90d authored by Joanne Hugé's avatar Joanne Hugé

Make the code compile with XDP on

parent b1f3a35a
......@@ -27,6 +27,12 @@ CFLAGS += -std=gnu99
LDFLAGS = -pthread
ifeq ($(WITH_XDP),)
else
CFLAGS += -D WITH_XDP
LDFLAGS += -L/usr/lib -lbpf
endif
vpath %.c $(SRCDIR)
$(SERVER_PROG): $(SERVER_OBJS)
......
......@@ -3,8 +3,10 @@
#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>
......@@ -12,6 +14,7 @@
#include <net/if.h>
#include <netdb.h>
#include <netinet/in.h>
#include <poll.h>
#include <pthread.h>
#include <sched.h>
#include <signal.h>
......@@ -23,13 +26,34 @@
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
#include "send_packet.h"
#include <net/if.h>
#include <netdb.h>
#include <sys/mman.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include "recv_packet.h"
#include "utilities.h"
#ifdef WITH_XDP
#include <linux/if_ether.h>
#include <linux/if_link.h>
#include <linux/if_xdp.h>
#include <linux/ip.h>
#include <linux/udp.h>
#include <bpf/bpf.h>
#include <bpf/libbpf.h>
#include <bpf/xsk.h>
#endif
static void fill_histograms(packet_info_t *packet_info, int64_t histograms[NB_HISTOGRAMS][MAX_HIST_VAL]);
static void open_xdp_socket(void);
static char rx_buffer[MAX_BUFFER_SIZE];
static int sock_fd;
......@@ -168,23 +192,67 @@ packet_info_t recv_udp_packet(int use_timestamps, int use_histograms, int64_t hi
return packet_info;
}
#ifdef WITH_XDP
static int xdp_flags = XDP_FLAGS_DRV_MODE;
static struct pollfd fds[1] = { 0 };
static unsigned int ifindex;
static struct xdpsock xdp_socket;
static void open_xdp_socket(char *network_if) {
struct xsk_socket_config xsk_cfg;
uint32_t idx;
int ret, i;
/* 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;
xsk_cfg.bind_flags = 0;
ret = xsk_socket__create(&xdp_socket.xsk, network_if,
0, xdp_socket.umem.umem, &xdp_socket.rx,
&xdp_socket.tx, &xsk_cfg);
if (ret)
err("xsk_socket__create() failed");
/* Add some buffers */
ret = xsk_ring_prod__reserve(&xdp_socket.umem.fq,
XSK_RING_PROD__DEFAULT_NUM_DESCS,
&idx);
if (ret != XSK_RING_PROD__DEFAULT_NUM_DESCS)
err("xsk_ring_prod__reserve() failed");
for (i = 0; i < XSK_RING_PROD__DEFAULT_NUM_DESCS; i++)
*xsk_ring_prod__fill_addr(&xdp_socket.umem.fq, idx++) =
i * FRAME_SIZE;
xsk_ring_prod__submit(&xdp_socket.umem.fq,
XSK_RING_PROD__DEFAULT_NUM_DESCS);
fds[0].fd = xsk_socket__fd(xdp_socket.xsk);
fds[0].events = POLLIN;
}
#endif
/*
* Init XDP socket
*/
void setup_xdp_socket(void)
{
void init_xdp_recv(char *network_if) {
#ifdef WITH_XDP
int ret, prog_fd, xsks_map = 0;
struct bpf_prog_load_attr prog_load_attr = {
.prog_type = BPF_PROG_TYPE_XDP,
.file = "xdp_kern.o",
.file = "xdp_kern.o",
};
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,
.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,
.flags = 0,
};
struct bpf_object *obj;
struct bpf_map *map;
......@@ -192,48 +260,48 @@ void setup_xdp_socket(void)
ret = bpf_prog_load_xattr(&prog_load_attr, &obj, &prog_fd);
if (ret || prog_fd < 0)
err("bpf_prog_load_xattr() failed");
err("bpf_prog_load_xattr() failed");
map = bpf_object__find_map_by_name(obj, "xsks_map");
xsks_map = bpf_map__fd(map);
if (xsks_map < 0)
err("No xsks_map found!");
err("No xsks_map found!");
ifindex = if_nametoindex(interface);
ifindex = if_nametoindex(network_if);
if (!ifindex)
err_errno("if_nametoindex() failed");
err_errno("if_nametoindex() failed");
/* Use XDP _only_ in conjuction with driver assisted mode */
ret = bpf_set_link_xdp_fd(ifindex, prog_fd, xdp_flags());
ret = bpf_set_link_xdp_fd(ifindex, prog_fd, xdp_flags);
if (ret)
err("bpf_set_link_xdp_fd() failed");
err("bpf_set_link_xdp_fd() failed");
/* 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");
err_errno("posix_memalign() failed");
ret = xsk_umem__create(&xdp_socket.umem.umem, buffer,
NUM_FRAMES * FRAME_SIZE, &xdp_socket.umem.fq,
&xdp_socket.umem.cq, &cfg);
if (ret)
err("xsk_umem__create() failed");
err("xsk_umem__create() failed");
xdp_socket.umem.buffer = buffer;
/* Open and bind socket */
open_xdp_socket();
open_xdp_socket(network_if);
#endif
}
/*
* Receive XDP socket
*/
void recv_xdp_packet(void) {
int recv_xdp_packet(struct timespec * ts) {
#ifdef WITH_XDP
char *buffer;
long long tx_time, diff;
struct timespec ts;
unsigned int received;
uint64_t addr;
uint32_t idx_rx = 0, len, idx;
......@@ -241,9 +309,9 @@ void recv_xdp_packet(void) {
ret = poll(fds, 1, -1);
if (ret == 0)
return;
return 1;
if (ret < 0)
error(EXIT_FAILURE, errno, "poll failed");
error(EXIT_FAILURE, errno, "poll failed");
/*
* Process packets: One at a time is enough for cyclic apps. Just
......@@ -252,89 +320,30 @@ void recv_xdp_packet(void) {
*/
received = xsk_ring_cons__peek(&xdp_socket.rx, 1, &idx_rx);
if (!received)
return;
return 1;
/* Get current time */
ret = clock_gettime(CLOCK_TAI, &ts);
clock_gettime(CLOCK_MONOTONIC, ts);
if (received != 1)
error(EXIT_FAILURE, errno, "Received more packets than expected");
/* Get the packet */
addr = xsk_ring_cons__rx_desc(&xdp_socket.rx, idx_rx)->addr;
len = xsk_ring_cons__rx_desc(&xdp_socket.rx, idx_rx)->len;
/* Parse it */
buffer = parse_raw_packet(xsk_umem__add_offset_to_addr(addr), len);
if (!buffer)
return;
/* Decode */
ret = sscanf(buffer, "KURT: %lld", &tx_time);
if (ret != 1) {
log_err("Failed to decode package");
return;
}
error(EXIT_FAILURE, errno, "Received more packets than expected");
/* Cleanup */
xsk_ring_cons__release(&xdp_socket.rx, received);
/* Add that particular buffer back to the fill queue */
if (xsk_prod_nb_free(&xdp_socket.umem.fq, received)) {
ret = xsk_ring_prod__reserve(&xdp_socket.umem.fq, received, &idx);
ret = xsk_ring_prod__reserve(&xdp_socket.umem.fq, received, &idx);
if (ret != received)
err("xsk_ring_prod__reserve() failed");
if (ret != received)
err("xsk_ring_prod__reserve() failed");
*xsk_ring_prod__fill_addr(&xdp_socket.umem.fq, idx) =
xsk_umem__extract_addr(addr);
xsk_ring_prod__submit(&xdp_socket.umem.fq, received);
}
*xsk_ring_prod__fill_addr(&xdp_socket.umem.fq, idx) =
xsk_umem__extract_addr(addr);
/* Update stats */
diff = update_stats(&ts, tx_time);
if (break_value_ns && diff > break_value_ns) {
stop_tracing();
stop = 1;
break;
xsk_ring_prod__submit(&xdp_socket.umem.fq, received);
}
#endif
}
static void open_xdp_socket(void)
{
struct xsk_socket_config xsk_cfg;
uint32_t idx;
int ret, i;
/* 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();
xsk_cfg.bind_flags = 0;
ret = xsk_socket__create(&xdp_socket.xsk, interface,
queue, xdp_socket.umem.umem, &xdp_socket.rx,
&xdp_socket.tx, &xsk_cfg);
if (ret)
err("xsk_socket__create() failed");
/* Add some buffers */
ret = xsk_ring_prod__reserve(&xdp_socket.umem.fq,
XSK_RING_PROD__DEFAULT_NUM_DESCS,
&idx);
if (ret != XSK_RING_PROD__DEFAULT_NUM_DESCS)
err("xsk_ring_prod__reserve() failed");
for (i = 0; i < XSK_RING_PROD__DEFAULT_NUM_DESCS; i++)
*xsk_ring_prod__fill_addr(&xdp_socket.umem.fq, idx++) =
i * FRAME_SIZE;
xsk_ring_prod__submit(&xdp_socket.umem.fq,
XSK_RING_PROD__DEFAULT_NUM_DESCS);
return 0;
}
static void fill_histograms(packet_info_t *packet_info, int64_t histograms[NB_HISTOGRAMS][MAX_HIST_VAL]) {
......
......@@ -3,10 +3,30 @@
#include "utilities.h"
#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
int init_udp_recv(int use_timestamps, char *network_if);
packet_info_t recv_udp_packet(int use_timestamps, int use_histograms, int64_t histograms[NB_HISTOGRAMS][MAX_HIST_VAL]);
void setup_xdp_socket(void);
void recv_xdp_packet(void);
void init_xdp_recv(char *network_if);
int recv_xdp_packet(struct timespec *ts);
#endif
......@@ -28,18 +28,6 @@
#include "send_packet.h"
#include "utilities.h"
#ifdef WITH_XDP
#include <linux/if_link.h>
#include <linux/if_xdp.h>
#include <linux/if_ether.h>
#include <linux/udp.h>
#include <linux/ip.h>
#include <bpf/bpf.h>
#include <bpf/xsk.h>
#include <bpf/libbpf.h>
#endif
// Structs
typedef struct thread_stat {
......@@ -74,8 +62,6 @@ static void process_options(int argc, char *argv[]);
static void print_histograms();
static void sighand(int sig_num);
static void setup_xdp_socket(void);
// Static variables
static int64_t histograms[NB_HISTOGRAMS][MAX_HIST_VAL];
......@@ -89,7 +75,8 @@ static int enable_affinity;
static int enable_timestamps;
enum TSNTask { RECV_PACKET_TASK,
RTT_TASK };
RTT_TASK,
XDP_TASK };
static enum TSNTask tsn_task;
struct timespec measures_start;
......@@ -181,6 +168,29 @@ static void *packet_receiving_thread(void *p) {
previous = current;
prev_packet_id = current_packet_id;
} else if (tsn_task == XDP_TASK) {
if(recv_xdp_packet(&current))
continue;
if (stats->packets_received) {
diff = calcdiff_ns(current, previous);
stats->min_interval = diff < stats->min_interval ? diff : stats->min_interval;
stats->max_interval = diff > stats->max_interval ? diff : stats->max_interval;
if (enable_histograms) {
dist_to_interval = (((int64_t)diff) - param->interval) / 1000;
dist_to_interval += MAX_HIST_VAL / 2;
if (dist_to_interval > ((int)MAX_HIST_VAL) || dist_to_interval < 0)
fprintf(stderr, "jitter higher than MAX_HIST_VAL: %" PRIi64 "\n", dist_to_interval);
else
histograms[2][dist_to_interval]++;
}
}
previous = current;
}
}
......@@ -221,12 +231,20 @@ int main(int argc, char *argv[]) {
// Catch breaks with sighand to print the histograms
init_signals(sighand, enable_histograms);
// Initialize the UDP packet receiving socket
init_udp_recv(enable_timestamps, network_config.network_if);
if (tsn_task == XDP_TASK) {
// Initialize the XDP packet receiving socket
init_xdp_recv(network_config.network_if);
// Initialize the UDP packet sending socket if RTT is measured
if (tsn_task == RTT_TASK)
init_udp_send(0, 0, 1, network_config.network_if, network_config.tx_buffer_len);
} else {
// Initialize the UDP packet receiving socket
init_udp_recv(enable_timestamps, network_config.network_if);
// Initialize the UDP packet sending socket if RTT is measured
if (tsn_task == RTT_TASK)
init_udp_send(0, 0, 1, network_config.network_if, network_config.tx_buffer_len);
}
// Create the real time thread
if (pthread_create(&thread, NULL, packet_receiving_thread, (void *)param))
......@@ -256,12 +274,11 @@ int main(int argc, char *argv[]) {
10, kernel_space_time,
4, stats->packet_info.data,
4, stats->lost_packets);
}
else {
} else {
printf("\n");
}
printf("\033[%dA", 1);
printf("\033[%dA", 1);
}
}
}
......@@ -359,7 +376,7 @@ static void process_options(int argc, char *argv[]) {
int network_if_specified = 0;
for (;;) {
int c = getopt(argc, argv, "ab:d:f:ghi:p:r:tv");
int c = getopt(argc, argv, "ab:d:f:ghi:p:r:tvx");
if (c == -1)
break;
......@@ -405,6 +422,9 @@ static void process_options(int argc, char *argv[]) {
case 'v':
main_param.verbose = 1;
break;
case 'x':
tsn_task = XDP_TASK;
break;
}
}
......
......@@ -8,6 +8,18 @@
#include <time.h>
#include <unistd.h>
#ifdef WITH_XDP
#include <linux/if_ether.h>
#include <linux/if_link.h>
#include <linux/if_xdp.h>
#include <linux/ip.h>
#include <linux/udp.h>
#include <bpf/bpf.h>
#include <bpf/libbpf.h>
#include <bpf/xsk.h>
#endif
#define NSEC_PER_SEC UINT64_C(1000000000)
#define SERVER_PORT "50000"
#define SERVER_PORT_INT 50000
......@@ -15,28 +27,13 @@
#define NB_HISTOGRAMS 3
#define MAX_BUFFER_SIZE 1024
// XDP
#ifdef WITH_XDP
#define NUM_FRAMES 4096
#define FRAME_SIZE XSK_UMEM__DEFAULT_FRAME_SIZE
unsigned int ifindex;
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 struct xdpsock xdp_socket;
#endif
#define err(...) \
do { \
fprintf(stderr, __VA_ARGS__); \
exit(EXIT_FAILURE); \
} while (0)
#define err_errno(...) error(EXIT_FAILURE, errno, __VA_ARGS__);
typedef struct packet_info {
uint64_t userspace_enter_ts;
......
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