-
Notifications
You must be signed in to change notification settings - Fork 89
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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 used to test schedulers using the XDP and DEQUEUE hooks. It does this using 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 until I have added a way to express priorities to flows from the trace files. For now, the WFQ uses my five-tuples flow implementation with a fixed weight of 256. The xdp_scheduler_tester program includes a -v flag that prints out the enqueued packet. This flag prints more information about each packet to determine if it is correct. It is helpful while changing the code, but I think I will change this behavior in the future because it does not add much for users of the tool. Another issue I will need help with is adding the libbpf logging to the project. I have added the logging.h and logging.c files to lib/util. However, we need to change the Makefiles to include the required dependencies for the logging.c file for it to work. Signed-off-by: Frey Alfredsson <[email protected]>
- Loading branch information
1 parent
ce71462
commit e6bc5cb
Showing
14 changed files
with
1,350 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
/* SPDX-License-Identifier: GPL-2.0 */ | ||
|
||
#include <stdio.h> | ||
#include <stdarg.h> | ||
|
||
#include <bpf/libbpf.h> | ||
#include <xdp/libxdp.h> | ||
|
||
#include "logging.h" | ||
#include "util.h" | ||
|
||
static enum logging_print_level log_level = LOG_INFO; | ||
|
||
static int print_func(enum logging_print_level level, const char *format, | ||
va_list args) | ||
{ | ||
if (level > log_level) | ||
return 0; | ||
|
||
return vfprintf(stderr, format, args); | ||
} | ||
|
||
static int libbpf_print_func(enum libbpf_print_level level, const char *format, | ||
va_list args) | ||
{ | ||
return print_func(level + 1, format, args); | ||
} | ||
|
||
static int libbpf_silent_func(__unused enum libbpf_print_level level, | ||
__unused const char *format, | ||
__unused va_list args) | ||
{ | ||
return 0; | ||
} | ||
|
||
static int libxdp_print_func(enum libxdp_print_level level, const char *format, | ||
va_list args) | ||
{ | ||
return print_func(level + 1, format, args); | ||
} | ||
|
||
static int libxdp_silent_func(__unused enum libxdp_print_level level, | ||
__unused const char *format, | ||
__unused va_list args) | ||
{ | ||
return 0; | ||
} | ||
|
||
#define __printf(a, b) __attribute__((format(printf, a, b))) | ||
|
||
__printf(2, 3) void logging_print(enum logging_print_level level, | ||
const char *format, ...) | ||
{ | ||
va_list args; | ||
|
||
va_start(args, format); | ||
print_func(level, format, args); | ||
va_end(args); | ||
} | ||
|
||
void init_lib_logging(void) | ||
{ | ||
libbpf_set_print(libbpf_print_func); | ||
libxdp_set_print(libxdp_print_func); | ||
} | ||
|
||
void silence_libbpf_logging(void) | ||
{ | ||
if (log_level < LOG_VERBOSE) | ||
libbpf_set_print(libbpf_silent_func); | ||
} | ||
|
||
void silence_libxdp_logging(void) | ||
{ | ||
if (log_level < LOG_VERBOSE) | ||
libxdp_set_print(libxdp_silent_func); | ||
} | ||
|
||
enum logging_print_level set_log_level(enum logging_print_level level) | ||
{ | ||
enum logging_print_level old_level = log_level; | ||
|
||
log_level = level; | ||
return old_level; | ||
} | ||
|
||
enum logging_print_level increase_log_level(void) | ||
{ | ||
if (log_level < LOG_VERBOSE) | ||
log_level++; | ||
return log_level; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
/* SPDX-License-Identifier: GPL-2.0 */ | ||
|
||
#ifndef __LOGGING_H | ||
#define __LOGGING_H | ||
|
||
/* This matches the libbpf logging levels, but with an additional VERBOSE level; | ||
* we demote all libbpf messages by one level so debug messages only show up on | ||
* VERBOSE. | ||
*/ | ||
enum logging_print_level { | ||
LOG_WARN, | ||
LOG_INFO, | ||
LOG_DEBUG, | ||
LOG_VERBOSE, | ||
}; | ||
|
||
extern void logging_print(enum logging_print_level level, const char *format, | ||
...) __attribute__((format(printf, 2, 3))); | ||
|
||
#define __pr(level, fmt, ...) \ | ||
do { \ | ||
logging_print(level, fmt, ##__VA_ARGS__); \ | ||
} while (0) | ||
|
||
#define pr_warn(fmt, ...) __pr(LOG_WARN, fmt, ##__VA_ARGS__) | ||
#define pr_info(fmt, ...) __pr(LOG_INFO, fmt, ##__VA_ARGS__) | ||
#define pr_debug(fmt, ...) __pr(LOG_DEBUG, fmt, ##__VA_ARGS__) | ||
|
||
void init_lib_logging(void); | ||
void silence_libbpf_logging(void); | ||
void silence_libxdp_logging(void); | ||
enum logging_print_level set_log_level(enum logging_print_level level); | ||
enum logging_print_level increase_log_level(); | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) | ||
|
||
USER_TARGETS := xdp_scheduler_tester | ||
BPF_TARGETS := $(patsubst %.c,%,$(wildcard *.bpf.c)) | ||
|
||
LIB_DIR = ../lib | ||
|
||
include $(LIB_DIR)/common.mk |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) | ||
|
||
#define EEXIST 17 /* File exists */ | ||
|
||
#define BPF_MAP_TYPE_PIFO_GENERIC 31 | ||
#define BPF_MAP_TYPE_PIFO_XDP 32 | ||
|
||
/* | ||
* bpf_packet_dequeue | ||
* | ||
* Dequeue the packet at the head of the PIFO in *map* and return a pointer | ||
* to the packet (or NULL if the PIFO is empty). | ||
* | ||
* Returns | ||
* On success, a pointer to the packet, or NULL if the PIFO is empty. The | ||
* packet pointer must be freed using *bpf_packet_drop()* or returning | ||
* the packet pointer. The *rank* pointer will be set to the rank of | ||
* the dequeued packet on success, or a negative error code on error. | ||
*/ | ||
static long (*bpf_packet_dequeue)(void *ctx, void *map, __u64 flags, __u64 *rank) = (void *) 194; | ||
static long (*bpf_packet_drop)(void *ctx, void *pkt) = (void *) 195; | ||
|
||
struct flow_address { | ||
struct in6_addr ip; | ||
__u16 port; | ||
__u16 reserved; | ||
}; | ||
|
||
struct network_tuple { | ||
struct flow_address saddr; | ||
struct flow_address daddr; | ||
__u16 proto; | ||
__u8 ipv; | ||
__u8 reserved; | ||
}; | ||
|
||
struct flow_state { | ||
__u32 pkts; | ||
__u32 finish_bytes; | ||
}; | ||
|
||
|
||
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 NULL; | ||
|
||
return bpf_map_lookup_elem(map, key); | ||
} | ||
|
||
static __always_inline int bpf_max(__u64 left, __u64 right) | ||
{ | ||
return right > left ? right : left; | ||
} | ||
|
||
|
||
/* | ||
* Maps an IPv4 address into an IPv6 address according to RFC 4291 sec 2.5.5.2 | ||
*/ | ||
static void map_ipv4_to_ipv6(struct in6_addr *ipv6, __be32 ipv4) | ||
{ | ||
__builtin_memset(&ipv6->in6_u.u6_addr8[0], 0x00, 10); | ||
__builtin_memset(&ipv6->in6_u.u6_addr8[10], 0xff, 2); | ||
ipv6->in6_u.u6_addr32[3] = ipv4; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
# Used for debugging the xdp_scheduler_tester syntax | ||
global bpf file=./xdp_scheduler_fifo.bpf.o | ||
|
||
udp eth proto=1 dst port=8080 # In-line comment | ||
udp eth proto=2 dst port=8081 payload length=32 | ||
udp eth proto=3 dst port=8082 repeat=2 | ||
dequeue udp eth proto=1 dst port=8080 | ||
dequeue udp eth proto=2 dst port=8081 payload length=32 | ||
dequeue udp eth proto=3 dst port=8082 repeat=2 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
// 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") | ||
void *dequeue_prog(struct dequeue_ctx *ctx) | ||
{ | ||
__u64 prio = 0; | ||
void *pkt = (void *) bpf_packet_dequeue(ctx, &pifo_map, 0, &prio); | ||
if (!pkt) | ||
return 0; | ||
|
||
return pkt; | ||
} | ||
|
||
char _license[] SEC("license") = "GPL"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
// 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_dst_port; | ||
__u16 prio = 0; | ||
|
||
/* Parse Ethernet and IP/IPv6 headers */ | ||
eth_type = parse_ethhdr(&nh, data_end, ð); | ||
if (eth_type == bpf_htons(ETH_P_IP)) { | ||
ip_type = parse_iphdr(&nh, data_end, &iphdr); | ||
if (ip_type != IPPROTO_UDP) | ||
goto err; | ||
} else if (eth_type == bpf_htons(ETH_P_IPV6)) { | ||
ip_type = parse_ip6hdr(&nh, data_end, &ipv6hdr); | ||
if (ip_type != IPPROTO_UDP) | ||
goto err; | ||
} else { | ||
goto err; | ||
} | ||
|
||
/* Parse UDP header */ | ||
if (parse_udphdr(&nh, data_end, &udphdr) < 0) | ||
goto err; | ||
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; | ||
|
||
|
||
bpf_printk("XDP PIFO scheduled with priority %d", prio); | ||
return bpf_redirect_map(&pifo_map, prio, 0); | ||
err: | ||
bpf_printk("XDP PIFO failed"); | ||
return XDP_DROP; | ||
} | ||
|
||
SEC("dequeue") | ||
void *dequeue_prog(struct dequeue_ctx *ctx) | ||
{ | ||
__u64 prio = 0; | ||
void *pkt = (void *) bpf_packet_dequeue(ctx, &pifo_map, 0, &prio); | ||
if (!pkt) | ||
return 0; | ||
return pkt; | ||
} | ||
|
||
char _license[] SEC("license") = "GPL"; |
Oops, something went wrong.