[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[RFC PATCH 4/6] ebpf: Added eBPF RSS loader.
From: |
Andrew Melnychenko |
Subject: |
[RFC PATCH 4/6] ebpf: Added eBPF RSS loader. |
Date: |
Mon, 2 Nov 2020 20:51:14 +0200 |
From: Andrew <andrew@daynix.com>
Added function that loads RSS eBPF program.
Added stub functions for RSS eBPF.
Added meson and configuration options.
Signed-off-by: Sameeh Jubran <sameeh@daynix.com>
Signed-off-by: Yuri Benditovich <yuri.benditovich@daynix.com>
Signed-off-by: Andrew Melnychenko <andrew@daynix.com>
---
configure | 36 ++++++++++
ebpf/ebpf-stub.c | 28 ++++++++
ebpf/ebpf_rss.c | 178 +++++++++++++++++++++++++++++++++++++++++++++++
ebpf/ebpf_rss.h | 30 ++++++++
ebpf/meson.build | 1 +
meson.build | 3 +
6 files changed, 276 insertions(+)
create mode 100644 ebpf/ebpf-stub.c
create mode 100644 ebpf/ebpf_rss.c
create mode 100644 ebpf/ebpf_rss.h
create mode 100644 ebpf/meson.build
diff --git a/configure b/configure
index 6df4306c88..bae4ea54f8 100755
--- a/configure
+++ b/configure
@@ -330,6 +330,7 @@ vhost_scsi=""
vhost_vsock=""
vhost_user=""
vhost_user_fs=""
+bpf=""
kvm="auto"
hax="auto"
hvf="auto"
@@ -1210,6 +1211,10 @@ for opt do
;;
--enable-membarrier) membarrier="yes"
;;
+ --disable-bpf) bpf="no"
+ ;;
+ --enable-bpf) bpf="yes"
+ ;;
--disable-blobs) blobs="false"
;;
--with-pkgversion=*) pkgversion="$optarg"
@@ -1792,6 +1797,7 @@ disabled with --disable-FEATURE, default is enabled if
available:
vhost-kernel vhost kernel backend support
vhost-user vhost-user backend support
vhost-vdpa vhost-vdpa kernel backend support
+ bpf BPF kernel support
spice spice
rbd rados block device (rbd)
libiscsi iscsi support
@@ -5347,6 +5353,33 @@ else
membarrier=no
fi
+##########################################
+# check for usable bpf system call
+if test "$bpf" = ""; then
+ have_bpf=no
+ if test "$linux" = "yes" ; then
+ cat > $TMPC << EOF
+ #include <sys/syscall.h>
+ #include <linux/bpf.h>
+ #include <unistd.h>
+ #include <stdlib.h>
+ #include <string.h>
+ int main(void) {
+ union bpf_attr * attr = NULL;
+ syscall(__NR_bpf, BPF_PROG_LOAD, attr, sizeof(attr));
+ exit(0);
+ }
+EOF
+ if compile_prog "" "" ; then
+ have_bpf=yes
+ bpf=yes
+ fi
+ fi
+ if test "$have_bpf" = "no"; then
+ feature_not_found "bpf" "the bpf system call is not available"
+ fi
+fi
+
##########################################
# check if rtnetlink.h exists and is useful
have_rtnetlink=no
@@ -6279,6 +6312,9 @@ fi
if test "$membarrier" = "yes" ; then
echo "CONFIG_MEMBARRIER=y" >> $config_host_mak
fi
+if test "$bpf" = "yes" -a "$bigendian" != "yes"; then
+ echo "CONFIG_EBPF=y" >> $config_host_mak
+fi
if test "$signalfd" = "yes" ; then
echo "CONFIG_SIGNALFD=y" >> $config_host_mak
fi
diff --git a/ebpf/ebpf-stub.c b/ebpf/ebpf-stub.c
new file mode 100644
index 0000000000..281dc039d3
--- /dev/null
+++ b/ebpf/ebpf-stub.c
@@ -0,0 +1,28 @@
+#include "qemu/osdep.h"
+#include "ebpf/ebpf_rss.h"
+
+void ebpf_rss_init(struct EBPFRSSContext *ctx)
+{
+
+}
+
+bool ebpf_rss_is_loaded(struct EBPFRSSContext *ctx)
+{
+ return false;
+}
+
+bool ebpf_rss_load(struct EBPFRSSContext *ctx)
+{
+ return false;
+}
+
+bool ebpf_rss_set_all(struct EBPFRSSContext *ctx, struct EBPFRSSConfig *config,
+ uint16_t *indirections_table, uint8_t *toeplitz_key)
+{
+ return false;
+}
+
+void ebpf_rss_unload(struct EBPFRSSContext *ctx)
+{
+
+}
diff --git a/ebpf/ebpf_rss.c b/ebpf/ebpf_rss.c
new file mode 100644
index 0000000000..f3c948a7a0
--- /dev/null
+++ b/ebpf/ebpf_rss.c
@@ -0,0 +1,178 @@
+#include "qemu/osdep.h"
+#include "qemu/error-report.h"
+
+#include "hw/virtio/virtio-net.h" /* VIRTIO_NET_RSS_MAX_TABLE_LEN */
+
+#include "ebpf/ebpf_rss.h"
+#include "ebpf/ebpf.h"
+#include "ebpf/tun_rss_steering.h"
+#include "trace.h"
+
+void ebpf_rss_init(struct EBPFRSSContext *ctx)
+{
+ if (ctx != NULL) {
+ ctx->program_fd = -1;
+ }
+}
+
+bool ebpf_rss_is_loaded(struct EBPFRSSContext *ctx)
+{
+ return ctx != NULL && ctx->program_fd >= 0;
+}
+
+bool ebpf_rss_load(struct EBPFRSSContext *ctx)
+{
+ if (ctx == NULL) {
+ return false;
+ }
+
+ ctx->map_configuration =
+ bpf_create_map(BPF_MAP_TYPE_ARRAY, sizeof(uint32_t),
+ sizeof(struct EBPFRSSConfig), 1);
+ if (ctx->map_configuration < 0) {
+ trace_ebpf_error("eBPF RSS", "can not create MAP for configurations");
+ goto l_conf_create;
+ }
+ ctx->map_toeplitz_key =
+ bpf_create_map(BPF_MAP_TYPE_ARRAY, sizeof(uint32_t),
+ VIRTIO_NET_RSS_MAX_KEY_SIZE, 1);
+ if (ctx->map_toeplitz_key < 0) {
+ trace_ebpf_error("eBPF RSS", "can not create MAP for toeplitz key");
+ goto l_toe_create;
+ }
+
+ ctx->map_indirections_table =
+ bpf_create_map(BPF_MAP_TYPE_ARRAY, sizeof(uint32_t),
+ sizeof(uint16_t), VIRTIO_NET_RSS_MAX_TABLE_LEN);
+ if (ctx->map_indirections_table < 0) {
+ trace_ebpf_error("eBPF RSS", "can not create MAP for indirections
table");
+ goto l_table_create;
+ }
+
+ bpf_fixup_mapfd(reltun_rss_steering,
+ sizeof(reltun_rss_steering) / sizeof(struct fixup_mapfd_t),
+ instun_rss_steering,
+ sizeof(instun_rss_steering) / sizeof(struct bpf_insn),
+ "tap_rss_map_configurations", ctx->map_configuration);
+
+ bpf_fixup_mapfd(reltun_rss_steering,
+ sizeof(reltun_rss_steering) / sizeof(struct fixup_mapfd_t),
+ instun_rss_steering,
+ sizeof(instun_rss_steering) / sizeof(struct bpf_insn),
+ "tap_rss_map_toeplitz_key", ctx->map_toeplitz_key);
+
+ bpf_fixup_mapfd(reltun_rss_steering,
+ sizeof(reltun_rss_steering) / sizeof(struct fixup_mapfd_t),
+ instun_rss_steering,
+ sizeof(instun_rss_steering) / sizeof(struct bpf_insn),
+ "tap_rss_map_indirection_table", ctx->map_indirections_table);
+
+ ctx->program_fd =
+ bpf_prog_load(BPF_PROG_TYPE_SOCKET_FILTER, instun_rss_steering,
+ sizeof(instun_rss_steering) / sizeof(struct bpf_insn),
+ "GPL");
+ if (ctx->program_fd < 0) {
+ trace_ebpf_error("eBPF RSS", "can not load eBPF program");
+ goto l_prog_load;
+ }
+
+ return true;
+l_prog_load:
+ close(ctx->map_indirections_table);
+l_table_create:
+ close(ctx->map_toeplitz_key);
+l_toe_create:
+ close(ctx->map_configuration);
+l_conf_create:
+ return false;
+}
+
+static bool ebpf_rss_set_config(struct EBPFRSSContext *ctx,
+ struct EBPFRSSConfig *config)
+{
+ if (!ebpf_rss_is_loaded(ctx)) {
+ return false;
+ }
+ uint32_t map_key = 0;
+ if (bpf_update_elem(ctx->map_configuration,
+ &map_key, config, BPF_ANY) < 0) {
+ return false;
+ }
+ return true;
+}
+
+static bool ebpf_rss_set_indirections_table(struct EBPFRSSContext *ctx,
+ uint16_t *indirections_table,
+ size_t len)
+{
+ if (!ebpf_rss_is_loaded(ctx) || indirections_table == NULL ||
+ len > VIRTIO_NET_RSS_MAX_TABLE_LEN) {
+ return false;
+ }
+ uint32_t i = 0;
+
+ for (; i < len; ++i) {
+ if (bpf_update_elem(ctx->map_indirections_table, &i,
+ indirections_table + i, BPF_ANY) < 0) {
+ return false;
+ }
+ }
+ return true;
+}
+
+static bool ebpf_rss_set_toepliz_key(struct EBPFRSSContext *ctx,
+ uint8_t *toeplitz_key)
+{
+ if (!ebpf_rss_is_loaded(ctx) || toeplitz_key == NULL) {
+ return false;
+ }
+ uint32_t map_key = 0;
+
+ /* prepare toeplitz key */
+ uint8_t toe[VIRTIO_NET_RSS_MAX_KEY_SIZE] = {};
+ memcpy(toe, toeplitz_key, VIRTIO_NET_RSS_MAX_KEY_SIZE);
+ *(uint32_t *)toe = ntohl(*(uint32_t *)toe);
+
+ if (bpf_update_elem(ctx->map_toeplitz_key, &map_key, toe,
+ BPF_ANY) < 0) {
+ return false;
+ }
+ return true;
+}
+
+bool ebpf_rss_set_all(struct EBPFRSSContext *ctx, struct EBPFRSSConfig *config,
+ uint16_t *indirections_table, uint8_t *toeplitz_key)
+{
+ if (!ebpf_rss_is_loaded(ctx) || config == NULL ||
+ indirections_table == NULL || toeplitz_key == NULL) {
+ return false;
+ }
+
+ if (!ebpf_rss_set_config(ctx, config)) {
+ return false;
+ }
+
+ if (!ebpf_rss_set_indirections_table(ctx, indirections_table,
+ config->indirections_len)) {
+ return false;
+ }
+
+ if (!ebpf_rss_set_toepliz_key(ctx, toeplitz_key)) {
+ return false;
+ }
+
+ return true;
+}
+
+void ebpf_rss_unload(struct EBPFRSSContext *ctx)
+{
+ if (!ebpf_rss_is_loaded(ctx)) {
+ return;
+ }
+
+ close(ctx->program_fd);
+ close(ctx->map_configuration);
+ close(ctx->map_toeplitz_key);
+ close(ctx->map_indirections_table);
+ ctx->program_fd = -1;
+}
diff --git a/ebpf/ebpf_rss.h b/ebpf/ebpf_rss.h
new file mode 100644
index 0000000000..ffed7b571a
--- /dev/null
+++ b/ebpf/ebpf_rss.h
@@ -0,0 +1,30 @@
+#ifndef QEMU_EBPF_RSS_H
+#define QEMU_EBPF_RSS_H
+
+struct EBPFRSSContext {
+ int program_fd;
+ int map_configuration;
+ int map_toeplitz_key;
+ int map_indirections_table;
+};
+
+struct EBPFRSSConfig {
+ uint8_t redirect;
+ uint8_t populate_hash;
+ uint32_t hash_types;
+ uint16_t indirections_len;
+ uint16_t default_queue;
+};
+
+void ebpf_rss_init(struct EBPFRSSContext *ctx);
+
+bool ebpf_rss_is_loaded(struct EBPFRSSContext *ctx);
+
+bool ebpf_rss_load(struct EBPFRSSContext *ctx);
+
+bool ebpf_rss_set_all(struct EBPFRSSContext *ctx, struct EBPFRSSConfig *config,
+ uint16_t *indirections_table, uint8_t *toeplitz_key);
+
+void ebpf_rss_unload(struct EBPFRSSContext *ctx);
+
+#endif /* QEMU_EBPF_RSS_H */
diff --git a/ebpf/meson.build b/ebpf/meson.build
new file mode 100644
index 0000000000..10f4bc9ca8
--- /dev/null
+++ b/ebpf/meson.build
@@ -0,0 +1 @@
+specific_ss.add(when: 'CONFIG_EBPF', if_true: files('ebpf_rss.c', 'ebpf.c'),
if_false: files('ebpf-stub.c'))
diff --git a/meson.build b/meson.build
index 47e32e1fcb..d0ea1a0e9d 100644
--- a/meson.build
+++ b/meson.build
@@ -1368,6 +1368,7 @@ if have_system
'backends',
'backends/tpm',
'chardev',
+ 'ebpf',
'hw/9pfs',
'hw/acpi',
'hw/alpha',
@@ -1530,6 +1531,7 @@ subdir('accel')
subdir('plugins')
subdir('bsd-user')
subdir('linux-user')
+subdir('ebpf')
bsd_user_ss.add(files('gdbstub.c'))
specific_ss.add_all(when: 'CONFIG_BSD_USER', if_true: bsd_user_ss)
@@ -2093,6 +2095,7 @@ summary_info += {'vhost-vsock support':
config_host.has_key('CONFIG_VHOST_VSOCK'
summary_info += {'vhost-user support':
config_host.has_key('CONFIG_VHOST_KERNEL')}
summary_info += {'vhost-user-fs support':
config_host.has_key('CONFIG_VHOST_USER_FS')}
summary_info += {'vhost-vdpa support':
config_host.has_key('CONFIG_VHOST_VDPA')}
+summary_info += {'bpf support': config_host.has_key('CONFIG_EBPF')}
summary_info += {'Trace backends': config_host['TRACE_BACKENDS']}
if config_host['TRACE_BACKENDS'].split().contains('simple')
summary_info += {'Trace output file': config_host['CONFIG_TRACE_FILE'] +
'-<pid>'}
--
2.28.0
[RFC PATCH 6/6] docs: Added eBPF documentation., Andrew Melnychenko, 2020/11/02