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

WIP: start adding XDP sockets

parent 67101268
......@@ -29,6 +29,7 @@
#include "utilities.h"
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;
......@@ -49,6 +50,9 @@ static int set_if(char *network_if) {
return ifreq.ifr_ifindex;
}
/*
* Init UDP socket
*/
int init_udp_recv(int use_timestamps, char *network_if) {
int getaddrinfo_err;
int set_if_err;
......@@ -100,7 +104,7 @@ int init_udp_recv(int use_timestamps, char *network_if) {
}
/*
* Receives udp packets
* Receive UDP packet
*/
packet_info_t recv_udp_packet(int use_timestamps, int use_histograms, int64_t histograms[NB_HISTOGRAMS][MAX_HIST_VAL]) {
......@@ -164,6 +168,175 @@ packet_info_t recv_udp_packet(int use_timestamps, int use_histograms, int64_t hi
return packet_info;
}
/*
* Init XDP socket
*/
void setup_xdp_socket(void)
{
#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",
};
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,
};
struct bpf_object *obj;
struct bpf_map *map;
void *buffer = NULL;
ret = bpf_prog_load_xattr(&prog_load_attr, &obj, &prog_fd);
if (ret || prog_fd < 0)
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!");
ifindex = if_nametoindex(interface);
if (!ifindex)
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());
if (ret)
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");
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");
xdp_socket.umem.buffer = buffer;
/* Open and bind socket */
open_xdp_socket();
#endif
}
/*
* Receive XDP socket
*/
void recv_xdp_packet(void) {
#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;
int ret;
ret = poll(fds, 1, -1);
if (ret == 0)
return;
if (ret < 0)
error(EXIT_FAILURE, errno, "poll failed");
/*
* Process packets: One at a time is enough for cyclic apps. Just
* be sure, that the NIC queue is correctly confgured. ethtool can
* be used for that.
*/
received = xsk_ring_cons__peek(&xdp_socket.rx, 1, &idx_rx);
if (!received)
return;
/* Get current time */
ret = clock_gettime(CLOCK_TAI, &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;
}
/* 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);
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);
}
/* Update stats */
diff = update_stats(&ts, tx_time);
if (break_value_ns && diff > break_value_ns) {
stop_tracing();
stop = 1;
break;
}
#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);
}
static void fill_histograms(packet_info_t *packet_info, int64_t histograms[NB_HISTOGRAMS][MAX_HIST_VAL]) {
uint64_t user_space_time = packet_info->userspace_exit_ts - packet_info->userspace_enter_ts;
......
......@@ -6,4 +6,7 @@
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);
#endif
......@@ -28,6 +28,18 @@
#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 {
......@@ -62,6 +74,8 @@ 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];
......
......@@ -15,6 +15,29 @@
#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
typedef struct packet_info {
uint64_t userspace_enter_ts;
uint64_t userspace_exit_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