Skip to content

Commit

Permalink
Adds the draft of the XDP scheduler testing tool
Browse files Browse the repository at this point in the history
This commit contains the XDP scheduling framework. It consists of a
testing program called xdp_scheduler_tester, XDP and DEQUEUE schedulers,
and trace files that the xdp_scheduler_tester program uses to check the
XDP schedulers for correctness.

The FIFO and PIFO schedulers are fully functional in this commit.
However, it defines flows as UDP port numbers. However, future commits
will change the flow definition to a five-tuple instead.

The WFQ implementation is partially complete. It needs changes on the
dequeue hook and has a few verifier issues preventing the current
version from loading.

Signed-off-by: Frey Alfredsson <[email protected]>
  • Loading branch information
freysteinn committed Mar 7, 2022
1 parent ce71462 commit 8416368
Show file tree
Hide file tree
Showing 11 changed files with 1,133 additions and 0 deletions.
11 changes: 11 additions & 0 deletions xdp-scheduler-tester/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)

USER_TARGETS := xdp_scheduler_tester
BPF_TARGETS := $(patsubst %.c,%,$(wildcard *.bpf.c))

# Depend on bpftool for auto generating
#

LIB_DIR = ../lib

include $(LIB_DIR)/common.mk
28 changes: 28 additions & 0 deletions xdp-scheduler-tester/bpf_local_helpers.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#define EEXIST 17 /* File exists */

#define BPF_MAP_TYPE_PIFO 31

static long (*bpf_packet_dequeue)(void *ctx, void *map, __u64 flags) = (void *) 181;
static long (*bpf_packet_return)(void *ctx, void *pkt) = (void *) 183;

static __always_inline void *
bpf_map_lookup_or_try_init(void *map, const void *key, const void *init)
{
void *val;
long err;

val = bpf_map_lookup_elem(map, key);
if (val)
return val;

err = bpf_map_update_elem(map, key, init, BPF_NOEXIST);
if (err && err != -EEXIST)
return 0;

return bpf_map_lookup_elem(map, key);
}

static __always_inline int bpf_max(__u64 left, __u64 right)
{
return right > left ? right : left;
}
7 changes: 7 additions & 0 deletions xdp-scheduler-tester/xdp_debug.trace
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Used for debugging the xdp_scheduler_tester syntax
global bpf file=./xdp_scheduler_fifo.bpf.o

udp eth proto=2 dst port=8080 # In-line comment
udp eth proto=1 dst port=8080
dequeue udp eth proto=1 dst port=8080
dequeue udp eth proto=2 dst port=8080
7 changes: 7 additions & 0 deletions xdp-scheduler-tester/xdp_fifo.trace
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
global bpf file=./xdp_scheduler_fifo.bpf.o
udp dst port=8080
udp dst port=8081
udp dst port=8082
dequeue udp dst port=8080
dequeue udp dst port=8081
dequeue udp dst port=8082
7 changes: 7 additions & 0 deletions xdp-scheduler-tester/xdp_pifo.trace
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
global bpf file=./xdp_scheduler_pifo.bpf.o
udp dst port=8002
udp dst port=8000
udp dst port=8001
dequeue udp dst port=8000
dequeue udp dst port=8001
dequeue udp dst port=8002
96 changes: 96 additions & 0 deletions xdp-scheduler-tester/xdp_scheduler_fifo.bpf.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2022 Freysteinn Alfredsson <[email protected]> */

#include <vmlinux_local.h>
#include <linux/bpf.h>
#include <bpf/bpf_endian.h>
#include <bpf/bpf_helpers.h>
#include <xdp/parsing_helpers.h>

#include "bpf_local_helpers.h"

struct {
__uint(type, BPF_MAP_TYPE_PIFO);
__uint(key_size, sizeof(__u32));
__uint(value_size, sizeof(__u32));
__uint(max_entries, 1024);
} pifo_map SEC(".maps");

/* Simple FIFO */
SEC("xdp")
int enqueue_prog(struct xdp_md *xdp)
{
void *data = (void *)(long)xdp->data;
void *data_end = (void *)(long)xdp->data_end;
struct ethhdr *eth = data;

if (eth + 1 > data_end)
return XDP_DROP;

return bpf_redirect_map(&pifo_map, 0, 0);
}

SEC("dequeue")
int dequeue_prog(struct dequeue_ctx *ctx)
{
void *pkt = (void *) bpf_packet_dequeue(ctx, &pifo_map, 0);
if (!pkt)
return 0;
else
return bpf_packet_return(ctx, pkt);
}














/* Weighted Fair-Queueing */
/*
SEC("xdp")
int xdp_wfq(struct xdp_md *xdp)
{
void *data = (void *)(long)xdp->data;
void *data_end = (void *)(long)xdp->data_end;
struct ethhdr *eth = data;
__u16 proto;
__u16 pifo;
if (eth + 1 > data_end)
return XDP_DROP;
proto = bpf_ntohs(eth->h_proto);
if (proto == 0)
pifo = proto;
else if (proto == 1)
pifo = proto;
else
pifo = 2;
bpf_printk("Kern XDP prio %d", pifo);
return bpf_redirect_map(&pifo_map, 0, pifo);
}
SEC("dequeue")
int dequeue_wfq(struct dequeue_ctx *ctx)
{
void *pkt = (void *) bpf_packet_dequeue(ctx, &pifo_map, 0);
if (!pkt)
return 0;
else {
bpf_printk("Kern DEQUEUE");
return bpf_packet_return(ctx, pkt);
}
}
*/

char _license[] SEC("license") = "GPL";
82 changes: 82 additions & 0 deletions xdp-scheduler-tester/xdp_scheduler_pifo.bpf.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2022 Freysteinn Alfredsson <[email protected]> */

#include <vmlinux_local.h>
#include <linux/bpf.h>
#include <bpf/bpf_endian.h>
#include <bpf/bpf_helpers.h>
#include <xdp/parsing_helpers.h>

#include "bpf_local_helpers.h"

struct {
__uint(type, BPF_MAP_TYPE_PIFO);
__uint(key_size, sizeof(__u32));
__uint(value_size, sizeof(__u32));
__uint(max_entries, 1024);
} pifo_map SEC(".maps");

/* Simple PIFO strict priority */
SEC("xdp")
int enqueue_prog(struct xdp_md *xdp)
{
void *data_end = (void *)(long)xdp->data_end;
void *data = (void *)(long)xdp->data;
struct hdr_cursor nh = { .pos = data };
struct ethhdr *eth;
int eth_type;
struct iphdr *iphdr;
struct ipv6hdr *ipv6hdr;
int ip_type;
struct udphdr *udphdr;
int udp_len;
int udp_dst_port;
__u16 prio = 0;

/* Parse Ethernet and IP/IPv6 headers */
eth_type = parse_ethhdr(&nh, data_end, &eth);
if (eth_type == bpf_htons(ETH_P_IP)) {
ip_type = parse_iphdr(&nh, data_end, &iphdr);
if (ip_type != IPPROTO_UDP) {
goto out;
}
} else if (eth_type == bpf_htons(ETH_P_IPV6)) {
ip_type = parse_ip6hdr(&nh, data_end, &ipv6hdr);
if (ip_type != IPPROTO_UDP) {
goto out;
}
} else {
goto out;
}

/* Parse UDP header */
udp_len = parse_udphdr(&nh, data_end, &udphdr);
if (udp_len < 0) {
goto out;
}
udp_dst_port = bpf_htons(udphdr->dest);

/* Calculate scheduling priority */
prio = 0;
if (udp_dst_port == 8001)
prio = 1;
else if (udp_dst_port > 8001)
prio = 2;

return bpf_redirect_map(&pifo_map, prio, 0);
out:
return XDP_DROP;
}

SEC("dequeue")
int dequeue_prog(struct dequeue_ctx *ctx)
{
void *pkt = (void *) bpf_packet_dequeue(ctx, &pifo_map, 0);
if (!pkt)
return 0;
else {
return bpf_packet_return(ctx, pkt);
}
}

char _license[] SEC("license") = "GPL";
Loading

0 comments on commit 8416368

Please sign in to comment.