qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Andrew Melnychenko <andrew@daynix.com>
To: jasowang@redhat.com, mst@redhat.com
Cc: yan@daynix.com, yuri.benditovich@daynix.com,
	Andrew <andrew@daynix.com>, Sameeh Jubran <sameeh@daynix.com>,
	qemu-devel@nongnu.org
Subject: [RFC PATCH 4/6] ebpf: Added eBPF RSS loader.
Date: Mon,  2 Nov 2020 20:51:14 +0200	[thread overview]
Message-ID: <20201102185115.7425-5-andrew@daynix.com> (raw)
In-Reply-To: <20201102185115.7425-1-andrew@daynix.com>

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



  parent reply	other threads:[~2020-11-02 18:24 UTC|newest]

Thread overview: 36+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-11-02 18:51 [RFC PATCH 0/6] eBPF RSS support for virtio-net Andrew Melnychenko
2020-11-02 18:51 ` [RFC PATCH 1/6] net: Added SetSteeringEBPF method for NetClientState Andrew Melnychenko
2020-11-04  2:49   ` Jason Wang
2020-11-04  9:34     ` Yuri Benditovich
2020-11-02 18:51 ` [RFC PATCH 2/6] ebpf: Added basic eBPF API Andrew Melnychenko
2020-11-02 18:51 ` [RFC PATCH 3/6] ebpf: Added eBPF RSS program Andrew Melnychenko
2020-11-03 13:07   ` Daniel P. Berrangé
2020-11-02 18:51 ` Andrew Melnychenko [this message]
2020-11-02 18:51 ` [RFC PATCH 5/6] virtio-net: Added eBPF RSS to virtio-net Andrew Melnychenko
2020-11-04  3:09   ` Jason Wang
2020-11-04 11:07     ` Yuri Benditovich
2020-11-04 11:13       ` Daniel P. Berrangé
2020-11-04 15:51         ` Yuri Benditovich
2020-11-05  3:29       ` Jason Wang
2020-11-02 18:51 ` [RFC PATCH 6/6] docs: Added eBPF documentation Andrew Melnychenko
2020-11-04  3:15   ` Jason Wang
2020-11-05  3:56   ` Jason Wang
2020-11-05  9:40     ` Yuri Benditovich
2020-11-03  9:02 ` [RFC PATCH 0/6] eBPF RSS support for virtio-net Jason Wang
2020-11-03 10:32   ` Yuri Benditovich
2020-11-03 11:56     ` Daniel P. Berrangé
2020-11-04  2:15       ` Jason Wang
2020-11-04  2:07     ` Jason Wang
2020-11-04  9:31       ` Daniel P. Berrangé
2020-11-05  3:46         ` Jason Wang
2020-11-05  3:52           ` Jason Wang
2020-11-05  9:11             ` Yuri Benditovich
2020-11-05 10:01           ` Daniel P. Berrangé
2020-11-05 13:19             ` Daniel P. Berrangé
2020-11-05 15:13               ` Yuri Benditovich
2020-11-09  2:13                 ` Jason Wang
2020-11-09 13:33                   ` Yuri Benditovich
2020-11-10  2:23                     ` Jason Wang
2020-11-10  8:00                       ` Yuri Benditovich
2020-11-04 11:49       ` Yuri Benditovich
2020-11-04 12:04         ` Daniel P. Berrangé

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20201102185115.7425-5-andrew@daynix.com \
    --to=andrew@daynix.com \
    --cc=jasowang@redhat.com \
    --cc=mst@redhat.com \
    --cc=qemu-devel@nongnu.org \
    --cc=sameeh@daynix.com \
    --cc=yan@daynix.com \
    --cc=yuri.benditovich@daynix.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).