Skip to content

Commit 8416368

Browse files
committed
Adds the draft of the XDP scheduler testing tool
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]>
1 parent ce71462 commit 8416368

11 files changed

+1133
-0
lines changed

xdp-scheduler-tester/Makefile

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
2+
3+
USER_TARGETS := xdp_scheduler_tester
4+
BPF_TARGETS := $(patsubst %.c,%,$(wildcard *.bpf.c))
5+
6+
# Depend on bpftool for auto generating
7+
#
8+
9+
LIB_DIR = ../lib
10+
11+
include $(LIB_DIR)/common.mk
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#define EEXIST 17 /* File exists */
2+
3+
#define BPF_MAP_TYPE_PIFO 31
4+
5+
static long (*bpf_packet_dequeue)(void *ctx, void *map, __u64 flags) = (void *) 181;
6+
static long (*bpf_packet_return)(void *ctx, void *pkt) = (void *) 183;
7+
8+
static __always_inline void *
9+
bpf_map_lookup_or_try_init(void *map, const void *key, const void *init)
10+
{
11+
void *val;
12+
long err;
13+
14+
val = bpf_map_lookup_elem(map, key);
15+
if (val)
16+
return val;
17+
18+
err = bpf_map_update_elem(map, key, init, BPF_NOEXIST);
19+
if (err && err != -EEXIST)
20+
return 0;
21+
22+
return bpf_map_lookup_elem(map, key);
23+
}
24+
25+
static __always_inline int bpf_max(__u64 left, __u64 right)
26+
{
27+
return right > left ? right : left;
28+
}

xdp-scheduler-tester/xdp_debug.trace

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Used for debugging the xdp_scheduler_tester syntax
2+
global bpf file=./xdp_scheduler_fifo.bpf.o
3+
4+
udp eth proto=2 dst port=8080 # In-line comment
5+
udp eth proto=1 dst port=8080
6+
dequeue udp eth proto=1 dst port=8080
7+
dequeue udp eth proto=2 dst port=8080

xdp-scheduler-tester/xdp_fifo.trace

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
global bpf file=./xdp_scheduler_fifo.bpf.o
2+
udp dst port=8080
3+
udp dst port=8081
4+
udp dst port=8082
5+
dequeue udp dst port=8080
6+
dequeue udp dst port=8081
7+
dequeue udp dst port=8082

xdp-scheduler-tester/xdp_pifo.trace

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
global bpf file=./xdp_scheduler_pifo.bpf.o
2+
udp dst port=8002
3+
udp dst port=8000
4+
udp dst port=8001
5+
dequeue udp dst port=8000
6+
dequeue udp dst port=8001
7+
dequeue udp dst port=8002
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/* Copyright (c) 2022 Freysteinn Alfredsson <[email protected]> */
3+
4+
#include <vmlinux_local.h>
5+
#include <linux/bpf.h>
6+
#include <bpf/bpf_endian.h>
7+
#include <bpf/bpf_helpers.h>
8+
#include <xdp/parsing_helpers.h>
9+
10+
#include "bpf_local_helpers.h"
11+
12+
struct {
13+
__uint(type, BPF_MAP_TYPE_PIFO);
14+
__uint(key_size, sizeof(__u32));
15+
__uint(value_size, sizeof(__u32));
16+
__uint(max_entries, 1024);
17+
} pifo_map SEC(".maps");
18+
19+
/* Simple FIFO */
20+
SEC("xdp")
21+
int enqueue_prog(struct xdp_md *xdp)
22+
{
23+
void *data = (void *)(long)xdp->data;
24+
void *data_end = (void *)(long)xdp->data_end;
25+
struct ethhdr *eth = data;
26+
27+
if (eth + 1 > data_end)
28+
return XDP_DROP;
29+
30+
return bpf_redirect_map(&pifo_map, 0, 0);
31+
}
32+
33+
SEC("dequeue")
34+
int dequeue_prog(struct dequeue_ctx *ctx)
35+
{
36+
void *pkt = (void *) bpf_packet_dequeue(ctx, &pifo_map, 0);
37+
if (!pkt)
38+
return 0;
39+
else
40+
return bpf_packet_return(ctx, pkt);
41+
}
42+
43+
44+
45+
46+
47+
48+
49+
50+
51+
52+
53+
54+
55+
56+
/* Weighted Fair-Queueing */
57+
/*
58+
SEC("xdp")
59+
int xdp_wfq(struct xdp_md *xdp)
60+
{
61+
void *data = (void *)(long)xdp->data;
62+
void *data_end = (void *)(long)xdp->data_end;
63+
struct ethhdr *eth = data;
64+
__u16 proto;
65+
__u16 pifo;
66+
67+
if (eth + 1 > data_end)
68+
return XDP_DROP;
69+
70+
proto = bpf_ntohs(eth->h_proto);
71+
72+
if (proto == 0)
73+
pifo = proto;
74+
else if (proto == 1)
75+
pifo = proto;
76+
else
77+
pifo = 2;
78+
79+
bpf_printk("Kern XDP prio %d", pifo);
80+
return bpf_redirect_map(&pifo_map, 0, pifo);
81+
}
82+
83+
SEC("dequeue")
84+
int dequeue_wfq(struct dequeue_ctx *ctx)
85+
{
86+
void *pkt = (void *) bpf_packet_dequeue(ctx, &pifo_map, 0);
87+
if (!pkt)
88+
return 0;
89+
else {
90+
bpf_printk("Kern DEQUEUE");
91+
return bpf_packet_return(ctx, pkt);
92+
}
93+
}
94+
*/
95+
96+
char _license[] SEC("license") = "GPL";
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/* Copyright (c) 2022 Freysteinn Alfredsson <[email protected]> */
3+
4+
#include <vmlinux_local.h>
5+
#include <linux/bpf.h>
6+
#include <bpf/bpf_endian.h>
7+
#include <bpf/bpf_helpers.h>
8+
#include <xdp/parsing_helpers.h>
9+
10+
#include "bpf_local_helpers.h"
11+
12+
struct {
13+
__uint(type, BPF_MAP_TYPE_PIFO);
14+
__uint(key_size, sizeof(__u32));
15+
__uint(value_size, sizeof(__u32));
16+
__uint(max_entries, 1024);
17+
} pifo_map SEC(".maps");
18+
19+
/* Simple PIFO strict priority */
20+
SEC("xdp")
21+
int enqueue_prog(struct xdp_md *xdp)
22+
{
23+
void *data_end = (void *)(long)xdp->data_end;
24+
void *data = (void *)(long)xdp->data;
25+
struct hdr_cursor nh = { .pos = data };
26+
struct ethhdr *eth;
27+
int eth_type;
28+
struct iphdr *iphdr;
29+
struct ipv6hdr *ipv6hdr;
30+
int ip_type;
31+
struct udphdr *udphdr;
32+
int udp_len;
33+
int udp_dst_port;
34+
__u16 prio = 0;
35+
36+
/* Parse Ethernet and IP/IPv6 headers */
37+
eth_type = parse_ethhdr(&nh, data_end, &eth);
38+
if (eth_type == bpf_htons(ETH_P_IP)) {
39+
ip_type = parse_iphdr(&nh, data_end, &iphdr);
40+
if (ip_type != IPPROTO_UDP) {
41+
goto out;
42+
}
43+
} else if (eth_type == bpf_htons(ETH_P_IPV6)) {
44+
ip_type = parse_ip6hdr(&nh, data_end, &ipv6hdr);
45+
if (ip_type != IPPROTO_UDP) {
46+
goto out;
47+
}
48+
} else {
49+
goto out;
50+
}
51+
52+
/* Parse UDP header */
53+
udp_len = parse_udphdr(&nh, data_end, &udphdr);
54+
if (udp_len < 0) {
55+
goto out;
56+
}
57+
udp_dst_port = bpf_htons(udphdr->dest);
58+
59+
/* Calculate scheduling priority */
60+
prio = 0;
61+
if (udp_dst_port == 8001)
62+
prio = 1;
63+
else if (udp_dst_port > 8001)
64+
prio = 2;
65+
66+
return bpf_redirect_map(&pifo_map, prio, 0);
67+
out:
68+
return XDP_DROP;
69+
}
70+
71+
SEC("dequeue")
72+
int dequeue_prog(struct dequeue_ctx *ctx)
73+
{
74+
void *pkt = (void *) bpf_packet_dequeue(ctx, &pifo_map, 0);
75+
if (!pkt)
76+
return 0;
77+
else {
78+
return bpf_packet_return(ctx, pkt);
79+
}
80+
}
81+
82+
char _license[] SEC("license") = "GPL";

0 commit comments

Comments
 (0)