From patchwork Sun Feb 19 16:20:56 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Melnichenko X-Patchwork-Id: 1744717 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=daynix-com.20210112.gappssmtp.com header.i=@daynix-com.20210112.gappssmtp.com header.a=rsa-sha256 header.s=20210112 header.b=ZkOP37u8; dkim-atps=neutral Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4PKWV467S4z23yR for ; Mon, 20 Feb 2023 03:39:24 +1100 (AEDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1pTmhU-0006MD-Bq; Sun, 19 Feb 2023 11:38:08 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pTmhR-0006Hx-Sa for qemu-devel@nongnu.org; Sun, 19 Feb 2023 11:38:06 -0500 Received: from mail-ed1-x52c.google.com ([2a00:1450:4864:20::52c]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1pTmhQ-0006iK-1s for qemu-devel@nongnu.org; Sun, 19 Feb 2023 11:38:05 -0500 Received: by mail-ed1-x52c.google.com with SMTP id en26so2741988edb.13 for ; Sun, 19 Feb 2023 08:38:03 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=daynix-com.20210112.gappssmtp.com; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=LBTMUP17qgO4UCL3k98gY84dhgHwtRh8YSBQCxf5jZQ=; b=ZkOP37u8TiMVIi6rHFb/Tr/ZZxl1yoKrF3nW87YQ0QoIjuB/p0NQGVSFKMMsUmpgkn 2QY/tlI4STcD5JeYwNGWBJWXI5ybI72hAvxlymm4nbMhg4ncxc6wObDvsYK0tkfPx0cg Udra5CtP1hTymAypYmE+jLWBkrdYmqWAmRF3xdiXqrJdz6QywvNSBorXpoMgpHyGQhrG zqa9k+NUftDMpVFKor2zkdI0dYTM+M50dlYkSgTZS/kqABq9kWIEJktxZQYL0ew5VZY4 dMCe24LCEOwbARMTfXCr+OG4ivX+vQV8s7la/2gdEbbZmshXR8omwZnqgteS7aaF2nS1 8eKg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=LBTMUP17qgO4UCL3k98gY84dhgHwtRh8YSBQCxf5jZQ=; b=I+m0i4RKaMjuMktzct/OCmtVDl+Mh5TOx7iH8HdykoKI1XHK39V1ayoMqpazbxrxrb 1d0HTBmz7C65ghBvTvK2aazU6IXDYY/NH7UGdTnhruYvjFJhWO8xN5KpsjJ0qK4thWnW ur7pJO04B7lbOX1chwpkqmTiJVWasNJJf1n5Z/8HQFCt73sMQMYihT3MkQeg9EzJGj59 8yAjNP9aw468eRg3PLF4PDob+tQ4ZEac9X4VbJ3atsH60rErhrxMFibsHJV7LUsdnmab xTyjkD85zdnIJMUIs1GOwjBevlzeQg0Sdu6IdRQ5NrpMascjBuGR+XyFcqVwOrZ+3vCu 73gw== X-Gm-Message-State: AO0yUKUzzDscIkG/VsXUSnECwpjH+yP18/EXRdsUz8mRgB4MOH090+h/ +4feuBu2KgZ+7vLN6q9FSBWdsw== X-Google-Smtp-Source: AK7set8w8Fz+2D1K2BWo/8tSQaWhizsxzMmjyta44xmKy9XB8bDt7qkGjitJ6LTST71lRLdRkrsnGg== X-Received: by 2002:a17:906:9416:b0:878:72f7:bd99 with SMTP id q22-20020a170906941600b0087872f7bd99mr4609248ejx.6.1676824681692; Sun, 19 Feb 2023 08:38:01 -0800 (PST) Received: from localhost.localdomain ([193.33.38.48]) by smtp.gmail.com with ESMTPSA id l13-20020a1709066b8d00b008cdb0628991sm647516ejr.57.2023.02.19.08.37.58 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 19 Feb 2023 08:38:00 -0800 (PST) From: Andrew Melnychenko To: jasowang@redhat.com, mst@redhat.com, pbonzini@redhat.com, marcandre.lureau@redhat.com, berrange@redhat.com, thuth@redhat.com, philmd@linaro.org, armbru@redhat.com, eblake@redhat.com, qemu-devel@nongnu.org, toke@redhat.com, mprivozn@redhat.com Cc: yuri.benditovich@daynix.com, yan@daynix.com Subject: [PATCH 1/5] ebpf: Added eBPF initialization by fds and map update. Date: Sun, 19 Feb 2023 18:20:56 +0200 Message-Id: <20230219162100.174318-2-andrew@daynix.com> X-Mailer: git-send-email 2.39.1 In-Reply-To: <20230219162100.174318-1-andrew@daynix.com> References: <20230219162100.174318-1-andrew@daynix.com> MIME-Version: 1.0 Received-SPF: none client-ip=2a00:1450:4864:20::52c; envelope-from=andrew@daynix.com; helo=mail-ed1-x52c.google.com X-Spam_score_int: 14 X-Spam_score: 1.4 X-Spam_bar: + X-Spam_report: (1.4 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_SBL_CSS=3.335, SPF_HELO_NONE=0.001, SPF_NONE=0.001 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Changed eBPF map updates through mmaped array. Mmaped arrays provide direct access to map data. It should omit using bpf_map_update_elem() call, which may require capabilities that are not present. Also, eBPF RSS context may be initialized by file descriptors. virtio-net may provide fds passed by libvirt. Signed-off-by: Andrew Melnychenko --- ebpf/ebpf_rss-stub.c | 6 +++ ebpf/ebpf_rss.c | 120 ++++++++++++++++++++++++++++++++++--------- ebpf/ebpf_rss.h | 10 ++++ 3 files changed, 113 insertions(+), 23 deletions(-) diff --git a/ebpf/ebpf_rss-stub.c b/ebpf/ebpf_rss-stub.c index e71e229190..8d7fae2ad9 100644 --- a/ebpf/ebpf_rss-stub.c +++ b/ebpf/ebpf_rss-stub.c @@ -28,6 +28,12 @@ bool ebpf_rss_load(struct EBPFRSSContext *ctx) return false; } +bool ebpf_rss_load_fds(struct EBPFRSSContext *ctx, int program_fd, + int config_fd, int toeplitz_fd, int table_fd) +{ + return false; +} + bool ebpf_rss_set_all(struct EBPFRSSContext *ctx, struct EBPFRSSConfig *config, uint16_t *indirections_table, uint8_t *toeplitz_key) { diff --git a/ebpf/ebpf_rss.c b/ebpf/ebpf_rss.c index cee658c158..08015fecb1 100644 --- a/ebpf/ebpf_rss.c +++ b/ebpf/ebpf_rss.c @@ -27,19 +27,68 @@ void ebpf_rss_init(struct EBPFRSSContext *ctx) { if (ctx != NULL) { ctx->obj = NULL; + ctx->program_fd = -1; } } bool ebpf_rss_is_loaded(struct EBPFRSSContext *ctx) { - return ctx != NULL && ctx->obj != NULL; + return ctx != NULL && (ctx->obj != NULL || ctx->program_fd != -1); +} + +static bool ebpf_rss_mmap(struct EBPFRSSContext *ctx) +{ + if (!ebpf_rss_is_loaded(ctx)) { + return false; + } + + ctx->mmap_configuration = mmap(NULL, qemu_real_host_page_size(), + PROT_READ | PROT_WRITE, MAP_SHARED, + ctx->map_configuration, 0); + if (ctx->mmap_configuration == MAP_FAILED) { + trace_ebpf_error("eBPF RSS", "can not mmap eBPF configuration array"); + return false; + } + ctx->mmap_toeplitz_key = mmap(NULL, qemu_real_host_page_size(), + PROT_READ | PROT_WRITE, MAP_SHARED, + ctx->map_toeplitz_key, 0); + if (ctx->mmap_toeplitz_key == MAP_FAILED) { + trace_ebpf_error("eBPF RSS", "can not mmap eBPF toeplitz key"); + goto toeplitz_fail; + } + ctx->mmap_indirections_table = mmap(NULL, qemu_real_host_page_size(), + PROT_READ | PROT_WRITE, MAP_SHARED, + ctx->map_indirections_table, 0); + if (ctx->mmap_indirections_table == MAP_FAILED) { + trace_ebpf_error("eBPF RSS", "can not mmap eBPF indirection table"); + goto indirection_fail; + } + + return true; + +indirection_fail: + munmap(ctx->mmap_toeplitz_key, qemu_real_host_page_size()); +toeplitz_fail: + munmap(ctx->mmap_configuration, qemu_real_host_page_size()); + return false; +} + +static void ebpf_rss_munmap(struct EBPFRSSContext *ctx) +{ + if (!ebpf_rss_is_loaded(ctx)) { + return; + } + + munmap(ctx->mmap_indirections_table, qemu_real_host_page_size()); + munmap(ctx->mmap_toeplitz_key, qemu_real_host_page_size()); + munmap(ctx->mmap_configuration, qemu_real_host_page_size()); } bool ebpf_rss_load(struct EBPFRSSContext *ctx) { struct rss_bpf *rss_bpf_ctx; - if (ctx == NULL) { + if (ctx == NULL || ebpf_rss_is_loaded(ctx)) { return false; } @@ -66,26 +115,51 @@ bool ebpf_rss_load(struct EBPFRSSContext *ctx) ctx->map_toeplitz_key = bpf_map__fd( rss_bpf_ctx->maps.tap_rss_map_toeplitz_key); + if (!ebpf_rss_mmap(ctx)) { + goto error; + } + return true; error: rss_bpf__destroy(rss_bpf_ctx); ctx->obj = NULL; + ctx->program_fd = -1; return false; } -static bool ebpf_rss_set_config(struct EBPFRSSContext *ctx, - struct EBPFRSSConfig *config) +bool ebpf_rss_load_fds(struct EBPFRSSContext *ctx, int program_fd, + int config_fd, int toeplitz_fd, int table_fd) { - uint32_t map_key = 0; + if (ctx == NULL || ebpf_rss_is_loaded(ctx)) { + return false; + } - if (!ebpf_rss_is_loaded(ctx)) { + if (program_fd < 0 || config_fd < 0 || toeplitz_fd < 0 || table_fd < 0) { return false; } - if (bpf_map_update_elem(ctx->map_configuration, - &map_key, config, 0) < 0) { + + ctx->program_fd = program_fd; + ctx->map_configuration = config_fd; + ctx->map_toeplitz_key = toeplitz_fd; + ctx->map_indirections_table = table_fd; + + if (!ebpf_rss_mmap(ctx)) { + ctx->program_fd = -1; return false; } + + return true; +} + +static bool ebpf_rss_set_config(struct EBPFRSSContext *ctx, + struct EBPFRSSConfig *config) +{ + if (!ebpf_rss_is_loaded(ctx)) { + return false; + } + + memcpy(ctx->mmap_configuration, config, sizeof(*config)); return true; } @@ -93,27 +167,19 @@ static bool ebpf_rss_set_indirections_table(struct EBPFRSSContext *ctx, uint16_t *indirections_table, size_t len) { - uint32_t i = 0; - if (!ebpf_rss_is_loaded(ctx) || indirections_table == NULL || len > VIRTIO_NET_RSS_MAX_TABLE_LEN) { return false; } - for (; i < len; ++i) { - if (bpf_map_update_elem(ctx->map_indirections_table, &i, - indirections_table + i, 0) < 0) { - return false; - } - } + memcpy(ctx->mmap_indirections_table, indirections_table, + sizeof(*indirections_table) * len); return true; } static bool ebpf_rss_set_toepliz_key(struct EBPFRSSContext *ctx, uint8_t *toeplitz_key) { - uint32_t map_key = 0; - /* prepare toeplitz key */ uint8_t toe[VIRTIO_NET_RSS_MAX_KEY_SIZE] = {}; @@ -123,10 +189,7 @@ static bool ebpf_rss_set_toepliz_key(struct EBPFRSSContext *ctx, memcpy(toe, toeplitz_key, VIRTIO_NET_RSS_MAX_KEY_SIZE); *(uint32_t *)toe = ntohl(*(uint32_t *)toe); - if (bpf_map_update_elem(ctx->map_toeplitz_key, &map_key, toe, - 0) < 0) { - return false; - } + memcpy(ctx->mmap_toeplitz_key, toe, VIRTIO_NET_RSS_MAX_KEY_SIZE); return true; } @@ -160,6 +223,17 @@ void ebpf_rss_unload(struct EBPFRSSContext *ctx) return; } - rss_bpf__destroy(ctx->obj); + ebpf_rss_munmap(ctx); + + if (ctx->obj) { + rss_bpf__destroy(ctx->obj); + } else { + close(ctx->program_fd); + close(ctx->map_configuration); + close(ctx->map_toeplitz_key); + close(ctx->map_indirections_table); + } + ctx->obj = NULL; + ctx->program_fd = -1; } diff --git a/ebpf/ebpf_rss.h b/ebpf/ebpf_rss.h index bf3f2572c7..239242b0d2 100644 --- a/ebpf/ebpf_rss.h +++ b/ebpf/ebpf_rss.h @@ -14,12 +14,19 @@ #ifndef QEMU_EBPF_RSS_H #define QEMU_EBPF_RSS_H +#define EBPF_RSS_MAX_FDS 4 + struct EBPFRSSContext { void *obj; int program_fd; int map_configuration; int map_toeplitz_key; int map_indirections_table; + + /* mapped eBPF maps for direct access to omit bpf_map_update_elem() */ + void *mmap_configuration; + void *mmap_toeplitz_key; + void *mmap_indirections_table; }; struct EBPFRSSConfig { @@ -36,6 +43,9 @@ bool ebpf_rss_is_loaded(struct EBPFRSSContext *ctx); bool ebpf_rss_load(struct EBPFRSSContext *ctx); +bool ebpf_rss_load_fds(struct EBPFRSSContext *ctx, int program_fd, + int config_fd, int toeplitz_fd, int table_fd); + bool ebpf_rss_set_all(struct EBPFRSSContext *ctx, struct EBPFRSSConfig *config, uint16_t *indirections_table, uint8_t *toeplitz_key); From patchwork Sun Feb 19 16:20:57 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Melnichenko X-Patchwork-Id: 1744718 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=daynix-com.20210112.gappssmtp.com header.i=@daynix-com.20210112.gappssmtp.com header.a=rsa-sha256 header.s=20210112 header.b=cTE8Bqd9; dkim-atps=neutral Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4PKWVS3Yc1z23yR for ; Mon, 20 Feb 2023 03:39:44 +1100 (AEDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1pTmhW-0006NQ-0z; Sun, 19 Feb 2023 11:38:10 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pTmhU-0006Mc-HA for qemu-devel@nongnu.org; Sun, 19 Feb 2023 11:38:08 -0500 Received: from mail-ed1-x531.google.com ([2a00:1450:4864:20::531]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1pTmhS-0006kQ-QY for qemu-devel@nongnu.org; Sun, 19 Feb 2023 11:38:08 -0500 Received: by mail-ed1-x531.google.com with SMTP id i31so1423535eda.12 for ; Sun, 19 Feb 2023 08:38:06 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=daynix-com.20210112.gappssmtp.com; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=cS2SfuOZUDUCnHCsD2utKdDjr/whiLBUbqxQeAy3dWs=; b=cTE8Bqd9WSkh7BTr0Ex07aec9q/A3Ut21NJaCIaXKLFdkwqdlIAiGrAe0p9Ti2T2lB 5rXt2OSz0XMfuAqOAP/iPY3sIKAVgJfuwuRba24jsHOpqZ0TDawNMQOx3goi+Fy4MIs8 fK/qRQuXzYjFLCW72ACe316eQLMtZnkIOhV9Z3UqN4XlpeYp2FcjKF+0FRYxP/dKxaXN 3sbFhPCXc+4ltB/mwlk9RkgM9y6GIf/t1+24Vc54mVUIe3ILNd1GaB8oAn5rxQqiruiH 8pCYnG7K2xLn51O4g+v744jeIuiR45bfFl5t/14ABv1dhQC0W25exG5b10xS76xlepMp y/7Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=cS2SfuOZUDUCnHCsD2utKdDjr/whiLBUbqxQeAy3dWs=; b=GGhS/mD9ysX4t0pzZEe5IatzxZ2oTmaHHJRw6YPegWA4msVIlxo7SrCYyXzzYoJT6H EMH5OlA47l1wxoAHdZsIkUX/CpLs0ZpsbxrHQBMHuBxb2IeRInMINMU8S3a8Cdcbzjwm Ew3aKzOGq4ZJsocUZy2Gh/GWy2yhASTdmwotJXaz5q29jJeTLfWeCXzxgbA1XnSpH9XG PV2krc7K0rzricu+Rqd0Vh6tgHLEg7Ro8JLV3ONIQO+MmamTEf00zjY7YQS8P7xFYhAT HB3BxQoO7hgbvp4rDrZmI40x30odiyeMl7PrgK0a0gjNHoHB5RkDn0fkFO4+sn6uvVNu A4ww== X-Gm-Message-State: AO0yUKVmyJdKPH7ddqY71Iy+FXzQ0UXBwvCn1Mn0S2NFyaOGOIAV09KC AkHTOXIry/X0SZkvQMzqZK9Mog== X-Google-Smtp-Source: AK7set+Mp6ggUZ67UvudCmv/WbjDXTe5Po9NMtdVjJcZsNfv2yDAf5akeWLM5wxRSbnaCcziI/Qbeg== X-Received: by 2002:a17:906:af1a:b0:880:a42d:dfb4 with SMTP id lx26-20020a170906af1a00b00880a42ddfb4mr5287323ejb.16.1676824685205; Sun, 19 Feb 2023 08:38:05 -0800 (PST) Received: from localhost.localdomain ([193.33.38.48]) by smtp.gmail.com with ESMTPSA id l13-20020a1709066b8d00b008cdb0628991sm647516ejr.57.2023.02.19.08.38.01 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 19 Feb 2023 08:38:03 -0800 (PST) From: Andrew Melnychenko To: jasowang@redhat.com, mst@redhat.com, pbonzini@redhat.com, marcandre.lureau@redhat.com, berrange@redhat.com, thuth@redhat.com, philmd@linaro.org, armbru@redhat.com, eblake@redhat.com, qemu-devel@nongnu.org, toke@redhat.com, mprivozn@redhat.com Cc: yuri.benditovich@daynix.com, yan@daynix.com Subject: [PATCH 2/5] virtio-net: Added property to load eBPF RSS with fds. Date: Sun, 19 Feb 2023 18:20:57 +0200 Message-Id: <20230219162100.174318-3-andrew@daynix.com> X-Mailer: git-send-email 2.39.1 In-Reply-To: <20230219162100.174318-1-andrew@daynix.com> References: <20230219162100.174318-1-andrew@daynix.com> MIME-Version: 1.0 Received-SPF: none client-ip=2a00:1450:4864:20::531; envelope-from=andrew@daynix.com; helo=mail-ed1-x531.google.com X-Spam_score_int: 14 X-Spam_score: 1.4 X-Spam_bar: + X-Spam_report: (1.4 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_SBL_CSS=3.335, SPF_HELO_NONE=0.001, SPF_NONE=0.001 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org eBPF RSS program and maps may now be passed during initialization. Initially was implemented for libvirt to launch qemu without permissions, and initialized eBPF program through the helper. Signed-off-by: Andrew Melnychenko --- hw/net/virtio-net.c | 77 ++++++++++++++++++++++++++++++++-- include/hw/virtio/virtio-net.h | 1 + 2 files changed, 74 insertions(+), 4 deletions(-) diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index 3ae909041a..0ab2cf33f9 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -42,6 +42,7 @@ #include "sysemu/sysemu.h" #include "trace.h" #include "monitor/qdev.h" +#include "monitor/monitor.h" #include "hw/pci/pci_device.h" #include "net_rx_pkt.h" #include "hw/virtio/vhost.h" @@ -1290,14 +1291,81 @@ static void virtio_net_detach_epbf_rss(VirtIONet *n) virtio_net_attach_ebpf_to_backend(n->nic, -1); } -static bool virtio_net_load_ebpf(VirtIONet *n) +static int virtio_net_get_ebpf_rss_fds(char *str, char *fds[], int nfds) +{ + char *ptr = str; + char *cur = NULL; + size_t len = strlen(str); + int i = 0; + + for (; i < nfds && ptr < str + len;) { + cur = strchr(ptr, ':'); + + if (cur == NULL) { + fds[i] = g_strdup(ptr); + } else { + fds[i] = g_strndup(ptr, cur - ptr); + } + + i++; + if (cur == NULL) { + break; + } else { + ptr = cur + 1; + } + } + + return i; +} + +static bool virtio_net_load_ebpf_fds(VirtIONet *n) { - if (!virtio_net_attach_ebpf_to_backend(n->nic, -1)) { - /* backend does't support steering ebpf */ + char *fds_strs[EBPF_RSS_MAX_FDS]; + int fds[EBPF_RSS_MAX_FDS]; + int nfds; + int ret = false; + Error *errp; + int i = 0; + + if (n == NULL || !n->ebpf_rss_fds) { return false; } - return ebpf_rss_load(&n->ebpf_rss); + nfds = virtio_net_get_ebpf_rss_fds(n->ebpf_rss_fds, + fds_strs, EBPF_RSS_MAX_FDS); + for (i = 0; i < nfds; i++) { + fds[i] = monitor_fd_param(monitor_cur(), fds_strs[i], &errp); + } + + if (nfds == EBPF_RSS_MAX_FDS) { + ret = ebpf_rss_load_fds(&n->ebpf_rss, fds[0], fds[1], fds[2], fds[3]); + } + + if (!ret) { + for (i = 0; i < nfds; i++) { + close(fds[i]); + } + } + + for (i = 0; i < nfds; i++) { + g_free(fds_strs[i]); + } + + return ret; +} + +static bool virtio_net_load_ebpf(VirtIONet *n) +{ + bool ret = true; + + if (virtio_net_attach_ebpf_to_backend(n->nic, -1)) { + if (!(n->ebpf_rss_fds + && virtio_net_load_ebpf_fds(n))) { + ret = ebpf_rss_load(&n->ebpf_rss); + } + } + + return ret; } static void virtio_net_unload_ebpf(VirtIONet *n) @@ -3868,6 +3936,7 @@ static Property virtio_net_properties[] = { VIRTIO_NET_F_RSS, false), DEFINE_PROP_BIT64("hash", VirtIONet, host_features, VIRTIO_NET_F_HASH_REPORT, false), + DEFINE_PROP_STRING("ebpf_rss_fds", VirtIONet, ebpf_rss_fds), DEFINE_PROP_BIT64("guest_rsc_ext", VirtIONet, host_features, VIRTIO_NET_F_RSC_EXT, false), DEFINE_PROP_UINT32("rsc_interval", VirtIONet, rsc_timeout, diff --git a/include/hw/virtio/virtio-net.h b/include/hw/virtio/virtio-net.h index ef234ffe7e..e10ce88f91 100644 --- a/include/hw/virtio/virtio-net.h +++ b/include/hw/virtio/virtio-net.h @@ -219,6 +219,7 @@ struct VirtIONet { VirtioNetRssData rss_data; struct NetRxPkt *rx_pkt; struct EBPFRSSContext ebpf_rss; + char *ebpf_rss_fds; }; size_t virtio_net_handle_ctrl_iov(VirtIODevice *vdev, From patchwork Sun Feb 19 16:20:58 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Melnichenko X-Patchwork-Id: 1744713 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=daynix-com.20210112.gappssmtp.com header.i=@daynix-com.20210112.gappssmtp.com header.a=rsa-sha256 header.s=20210112 header.b=CENDdJfF; dkim-atps=neutral Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4PKWTS1htHz23yR for ; Mon, 20 Feb 2023 03:38:50 +1100 (AEDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1pTmhb-0006Ou-RT; Sun, 19 Feb 2023 11:38:15 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pTmhY-0006O8-2Z for qemu-devel@nongnu.org; Sun, 19 Feb 2023 11:38:12 -0500 Received: from mail-ed1-x533.google.com ([2a00:1450:4864:20::533]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1pTmhV-0006ls-J4 for qemu-devel@nongnu.org; Sun, 19 Feb 2023 11:38:11 -0500 Received: by mail-ed1-x533.google.com with SMTP id et7so3541527edb.9 for ; Sun, 19 Feb 2023 08:38:09 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=daynix-com.20210112.gappssmtp.com; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=KXeG5Lesc64lZ0N6XEF8MFMqxfZtfauyqXJNBxusQSk=; b=CENDdJfF+n5gfZ2VCmcN0R1euN0Hz8NHHSlqhJDKaLm7OoxRUyESBqLJz580eObnrf i4vVOlBV2Gv4KSFTPbl40cK7jTliFt4N77bh6zKvfKRI5FE+vI+/c7wpNv0JW5U1MIzG OZ7EEC87oFoSpoIC8cpG4uYZVYTVAyj8dk1bAGV7JT1hlBLrIoL3pvQZobQEJNztwmrJ 0XQ0G/d3p5uVBNvdmfto2t09BIRa2Sr2FMLx2EjaP7gfEyKa17NP0qdy60AYi0slFzbB w/hLxAC70UDh9DXMaxoUNBQ2xmWcLLZDpp52hAtSbYbWrzKjDFQ/RwgpxLAmPRacCyCn QQeg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=KXeG5Lesc64lZ0N6XEF8MFMqxfZtfauyqXJNBxusQSk=; b=rkIuJQtuA8L2RkWVBr72iGlnNKBl0Bt1OU1S0sytRHcSYFV871Hm5banDzmCFsUdTL fPJsraj+DfXW8Mf25e9ID5Z4z6q40CRRn66bW5Y0fRb2LRZzkEvcH49hop7lc+25VYwZ B+VaAuwS/Qos+2rfP2Be9FALeHLSIR2gnhak772A107Ckj4/DdHNyD3rsTp6hvGc5A7V dHHKIvhmm5Fty+Zia67QIXAGyxulMTDPW1z1XRXKWNNH+2CAQp5wvZZFBkW+WvxQztia RyKLmJQNFlb+djj63f2lUG2eXrmr3ukQbygnPzcZXZh+PkLEgj7SaX6Ae7txme1ewNt/ K8Wg== X-Gm-Message-State: AO0yUKV4WRIFB/6Q5MrAgYWNDDwPVaQbA2YjJlcLyuMthtXhCw0wnuXF OmxyLmEi8dBrcHC0cc9lqRMGCw== X-Google-Smtp-Source: AK7set9s4MXAAJmrgwBqr+6oiKKIvMwU00sGIFlja7GM6psL9y70F6av4PpmerfAgnXvEC1Wt+RSYw== X-Received: by 2002:a17:907:97c3:b0:8af:ef00:b853 with SMTP id js3-20020a17090797c300b008afef00b853mr7098218ejc.73.1676824688208; Sun, 19 Feb 2023 08:38:08 -0800 (PST) Received: from localhost.localdomain ([193.33.38.48]) by smtp.gmail.com with ESMTPSA id l13-20020a1709066b8d00b008cdb0628991sm647516ejr.57.2023.02.19.08.38.05 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 19 Feb 2023 08:38:06 -0800 (PST) From: Andrew Melnychenko To: jasowang@redhat.com, mst@redhat.com, pbonzini@redhat.com, marcandre.lureau@redhat.com, berrange@redhat.com, thuth@redhat.com, philmd@linaro.org, armbru@redhat.com, eblake@redhat.com, qemu-devel@nongnu.org, toke@redhat.com, mprivozn@redhat.com Cc: yuri.benditovich@daynix.com, yan@daynix.com Subject: [PATCH 3/5] qmp: Added the helper stamp check. Date: Sun, 19 Feb 2023 18:20:58 +0200 Message-Id: <20230219162100.174318-4-andrew@daynix.com> X-Mailer: git-send-email 2.39.1 In-Reply-To: <20230219162100.174318-1-andrew@daynix.com> References: <20230219162100.174318-1-andrew@daynix.com> MIME-Version: 1.0 Received-SPF: none client-ip=2a00:1450:4864:20::533; envelope-from=andrew@daynix.com; helo=mail-ed1-x533.google.com X-Spam_score_int: 14 X-Spam_score: 1.4 X-Spam_bar: + X-Spam_report: (1.4 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_SBL_CSS=3.335, SPF_HELO_NONE=0.001, SPF_NONE=0.001 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Added a function to check the stamp in the helper. eBPF helper should have a special symbol that generates during the build. QEMU checks the helper and determines that it fits, so the helper will produce proper output. Signed-off-by: Andrew Melnychenko --- meson.build | 10 + monitor/meson.build | 1 + monitor/qemu-ebpf-rss-helper-stamp-utils.c | 322 +++++++++++++++++++++ monitor/qemu-ebpf-rss-helper-stamp-utils.h | 39 +++ 4 files changed, 372 insertions(+) create mode 100644 monitor/qemu-ebpf-rss-helper-stamp-utils.c create mode 100644 monitor/qemu-ebpf-rss-helper-stamp-utils.h diff --git a/meson.build b/meson.build index a76c855312..b409912aed 100644 --- a/meson.build +++ b/meson.build @@ -2868,6 +2868,16 @@ foreach d : hx_headers endforeach genh += hxdep +ebpf_rss_helper_stamp = custom_target( + 'qemu-ebpf-rss-helper-stamp.h', + output : 'qemu-ebpf-rss-helper-stamp.h', + input : 'ebpf/rss.bpf.skeleton.h', + command : [python, '-c', 'import hashlib; print(\'#define QEMU_EBPF_RSS_HELPER_STAMP qemuEbpfRssHelperStamp_{}\'.format(hashlib.sha1(open(\'@INPUT@\', \'rb\').read()).hexdigest()))'], + capture: true, +) + +genh += ebpf_rss_helper_stamp + ################### # Collect sources # ################### diff --git a/monitor/meson.build b/monitor/meson.build index ccb4d1a8e6..36de73414b 100644 --- a/monitor/meson.build +++ b/monitor/meson.build @@ -6,6 +6,7 @@ softmmu_ss.add(files( 'hmp.c', )) softmmu_ss.add([spice_headers, files('qmp-cmds.c')]) +softmmu_ss.add(files('qemu-ebpf-rss-helper-stamp-utils.c')) specific_ss.add(when: 'CONFIG_SOFTMMU', if_true: [files( 'hmp-cmds-target.c', 'hmp-target.c'), spice]) diff --git a/monitor/qemu-ebpf-rss-helper-stamp-utils.c b/monitor/qemu-ebpf-rss-helper-stamp-utils.c new file mode 100644 index 0000000000..23efc36ef0 --- /dev/null +++ b/monitor/qemu-ebpf-rss-helper-stamp-utils.c @@ -0,0 +1,322 @@ +/* + * QEMU helper stamp check utils. + * + * Developed by Daynix Computing LTD (http://www.daynix.com) + * + * Authors: + * Andrew Melnychenko + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Description: This file mostly implements helper stamp checking. + * The stamp is implemented in a similar way as in qemu modules. + * The helper should contain a specific symbol. + * Not in a similar way is symbol checking - here we parse + * the ELF file. For now, only eBPF helper contains + * the stamp, and the stamp is generated from + * sha1 ebpf/rss.bpf.skeleton.h (see meson.build). + */ + +#include "qemu/osdep.h" +#include "elf.h" +#include "qemu-ebpf-rss-helper-stamp-utils.h" + +#include + +#ifdef CONFIG_LINUX + +static void *file_allocate_and_read(int fd, off_t off, size_t size) +{ + void *data; + int err; + + if (fd < 0) { + return NULL; + } + + err = lseek(fd, off, SEEK_SET); + if (err < 0) { + return NULL; + } + + data = g_new0(char, size); + if (data == NULL) { + return NULL; + } + + err = read(fd, data, size); + if (err < 0) { + g_free(data); + return NULL; + } + + return data; +} + +static Elf64_Shdr *elf64_get_section_table(int fd, Elf64_Ehdr *elf_header) +{ + if (elf_header == NULL) { + return NULL; + } + return (Elf64_Shdr *)file_allocate_and_read(fd, elf_header->e_shoff, + elf_header->e_shnum * elf_header->e_shentsize); +} + +static Elf32_Shdr *elf32_get_section_table(int fd, Elf32_Ehdr *elf_header) +{ + if (elf_header == NULL) { + return NULL; + } + return (Elf32_Shdr *)file_allocate_and_read(fd, elf_header->e_shoff, + elf_header->e_shnum * elf_header->e_shentsize); +} + +static void *elf64_get_section_data(int fd, const Elf64_Shdr* section_header) +{ + if (fd < 0 || section_header == NULL) { + return NULL; + } + return file_allocate_and_read(fd, section_header->sh_offset, + section_header->sh_size); +} + +static void *elf32_get_section_data(int fd, const Elf32_Shdr* section_header) +{ + if (fd < 0 || section_header == NULL) { + return NULL; + } + return file_allocate_and_read(fd, section_header->sh_offset, + section_header->sh_size); +} + +static bool elf64_check_symbol_in_symbol_table(int fd, + Elf64_Shdr *section_table, + Elf64_Shdr *symbol_section, + const char *symbol) +{ + Elf64_Sym *symbol_table; + char *string_table; + uint32_t i; + bool ret = false; + + symbol_table = (Elf64_Sym *) elf64_get_section_data(fd, symbol_section); + if (symbol_table == NULL) { + return false; + } + + string_table = (char *) elf64_get_section_data( + fd, section_table + symbol_section->sh_link); + if (string_table == NULL) { + g_free(symbol_table); + return false; + } + + for (i = 0; i < (symbol_section->sh_size / sizeof(Elf64_Sym)); ++i) { + if (strncmp((string_table + symbol_table[i].st_name), + symbol, strlen(symbol)) == 0) + { + ret = true; + break; + } + } + + g_free(string_table); + g_free(symbol_table); + return ret; +} + +static bool elf32_check_symbol_in_symbol_table(int fd, + Elf32_Shdr *section_table, + Elf32_Shdr *symbol_section, + const char *symbol) +{ + Elf32_Sym *symbol_table; + char *string_table; + uint32_t i; + bool ret = false; + + symbol_table = (Elf32_Sym *) elf32_get_section_data(fd, symbol_section); + if (symbol_table == NULL) { + return false; + } + + string_table = (char *) elf32_get_section_data(fd, + section_table + symbol_section->sh_link); + if (string_table == NULL) { + g_free(symbol_table); + return false; + } + + for (i = 0; i < (symbol_section->sh_size / sizeof(Elf32_Sym)); ++i) { + if (strncmp((string_table + symbol_table[i].st_name), + symbol, strlen(symbol)) == 0) + { + ret = true; + break; + } + } + + g_free(string_table); + g_free(symbol_table); + return ret; +} + +static bool elf64_check_stamp(int fd, Elf64_Ehdr *elf_header, const char *stamp) +{ + Elf64_Shdr *section_table; + size_t i; + bool ret = false; + + section_table = elf64_get_section_table(fd, elf_header); + if (section_table == NULL) { + return false; + } + + for (i = 0; i < elf_header->e_shnum; ++i) { + if ((section_table[i].sh_type == SHT_SYMTAB) + || (section_table[i].sh_type == SHT_DYNSYM)) { + if (elf64_check_symbol_in_symbol_table(fd, section_table, + section_table + i, stamp)) { + ret = true; + break; + } + } + } + + g_free(section_table); + return ret; +} + +static bool elf32_check_stamp(int fd, Elf32_Ehdr *elf_header, const char *stamp) +{ + Elf32_Shdr *section_table; + size_t i; + bool ret = false; + + section_table = elf32_get_section_table(fd, elf_header); + if (section_table == NULL) { + return false; + } + + for (i = 0; i < elf_header->e_shnum; ++i) { + if ((section_table[i].sh_type == SHT_SYMTAB) + || (section_table[i].sh_type == SHT_DYNSYM)) { + if (elf32_check_symbol_in_symbol_table(fd, section_table, + section_table + i, stamp)) { + ret = true; + break; + } + } + } + + g_free(section_table); + return ret; +} + +static bool qemu_check_helper_stamp(const char *path, const char *stamp) +{ + int fd; + bool ret = false; + Elf64_Ehdr *elf_header; + + fd = open(path, O_RDONLY | O_SYNC); + if (fd < 0) { + return false; + } + + elf_header = (Elf64_Ehdr *)file_allocate_and_read( + fd, 0, sizeof(Elf64_Ehdr)); + if (elf_header == NULL) { + goto error; + } + + if (strncmp((char *)elf_header->e_ident, ELFMAG, SELFMAG)) { + g_free(elf_header); + goto error; + } + + if (elf_header->e_ident[EI_CLASS] == ELFCLASS64) { + ret = elf64_check_stamp(fd, elf_header, stamp); + } else if (elf_header->e_ident[EI_CLASS] == ELFCLASS32) { + ret = elf32_check_stamp(fd, (Elf32_Ehdr *)elf_header, stamp); + } + + g_free(elf_header); +error: + close(fd); + return ret; +} + +#else + +static bool qemu_check_helper_stamp(const char *path, const char *stamp) +{ + return false; +} + +#endif + +char *qemu_find_default_ebpf_rss_helper(void) +{ + char *qemu_exec = NULL; + char *qemu_dir = NULL; + char *helper = NULL; + + helper = g_build_filename(CONFIG_QEMU_HELPERDIR, + QEMU_DEFAULT_EBPF_RSS_HELPER_BIN_NAME, NULL); + if (g_access(helper, X_OK) == 0 + && qemu_check_helper_stamp(helper, QEMU_EBPF_RSS_HELPER_STAMP_STR)) { + return helper; + } + g_free(helper); + +#ifdef CONFIG_LINUX + qemu_exec = g_file_read_link("/proc/self/exe", NULL); +#else + qemu_exec = NULL; +#endif + if (qemu_exec != NULL) { + qemu_dir = g_path_get_dirname(qemu_exec); + g_free(qemu_exec); + helper = g_build_filename(qemu_dir, + QEMU_DEFAULT_EBPF_RSS_HELPER_BIN_NAME, NULL); + g_free(qemu_dir); + if (g_access(helper, X_OK) == 0 + && qemu_check_helper_stamp(helper, QEMU_EBPF_RSS_HELPER_STAMP_STR)) { + return helper; + } + g_free(helper); + } + + return NULL; +} + +char *qemu_check_suggested_ebpf_rss_helper(const char *path) +{ + char *helperbin = NULL; + struct stat statbuf; /* NOTE: use GStatBuf? */ + + /* check is dir or file */ + if (g_stat(path, &statbuf) < 0) { + return NULL; + } + + if (statbuf.st_mode & S_IFDIR) { + /* is dir */ + helperbin = g_build_filename(path, + QEMU_DEFAULT_EBPF_RSS_HELPER_BIN_NAME, NULL); + + } else if (statbuf.st_mode & S_IFREG) { + /* is file */ + helperbin = g_strdup(path); + } + + if (qemu_check_helper_stamp(helperbin, QEMU_EBPF_RSS_HELPER_STAMP_STR)) { + return helperbin; + } + + g_free(helperbin); + + return NULL; +} diff --git a/monitor/qemu-ebpf-rss-helper-stamp-utils.h b/monitor/qemu-ebpf-rss-helper-stamp-utils.h new file mode 100644 index 0000000000..7490568aa1 --- /dev/null +++ b/monitor/qemu-ebpf-rss-helper-stamp-utils.h @@ -0,0 +1,39 @@ +/* + * QEMU helper stamp check utils. + * + * Developed by Daynix Computing LTD (http://www.daynix.com) + * + * Authors: + * Andrew Melnychenko + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#ifndef QEMU_QEMU_HELPER_STAMP_UTILS_H +#define QEMU_QEMU_HELPER_STAMP_UTILS_H + +#include "qemu-ebpf-rss-helper-stamp.h" /* generated stamp per build */ + +#define QEMU_EBPF_RSS_HELPER_STAMP_STR stringify(QEMU_EBPF_RSS_HELPER_STAMP) + +#define QEMU_DEFAULT_EBPF_RSS_HELPER_BIN_NAME "qemu-ebpf-rss-helper" + +/** + * Trying to find the helper with a valid stamp in HELPERDIR + * or next to the QEMU binary. + * @return path to the eBPF RSS helper bin or NULL(helper not found). + */ +char *qemu_find_default_ebpf_rss_helper(void); + +/** + * Check the helper by the suggested path. The helper should have a valid stamp. + * @param path - it can be either a file or directory path. + * For the file - checks the stamp of the file. + * For the directory - looks for QEMU_DEFAULT_EBPF_RSS_HELPER_BIN_NAME + * and checks the stamp of that file. + * @return path to valid eBPF RSS helper bin or NULL. + */ +char *qemu_check_suggested_ebpf_rss_helper(const char *path); + +#endif /* QEMU_QEMU_HELPER_STAMP_UTILS_H */ From patchwork Sun Feb 19 16:20:59 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Melnichenko X-Patchwork-Id: 1744716 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=daynix-com.20210112.gappssmtp.com header.i=@daynix-com.20210112.gappssmtp.com header.a=rsa-sha256 header.s=20210112 header.b=79QX9xSL; dkim-atps=neutral Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4PKWV12w3Vz23yR for ; Mon, 20 Feb 2023 03:39:21 +1100 (AEDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1pTmhc-0006PO-GC; Sun, 19 Feb 2023 11:38:16 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pTmha-0006P6-Rq for qemu-devel@nongnu.org; Sun, 19 Feb 2023 11:38:15 -0500 Received: from mail-ed1-x534.google.com ([2a00:1450:4864:20::534]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1pTmhY-0006mU-FK for qemu-devel@nongnu.org; Sun, 19 Feb 2023 11:38:14 -0500 Received: by mail-ed1-x534.google.com with SMTP id k5so4176908edo.3 for ; Sun, 19 Feb 2023 08:38:12 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=daynix-com.20210112.gappssmtp.com; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=sUnT3ujPcgcf9Q4OleidIWlUvOyf8yl/vIkF0lAkYrk=; b=79QX9xSL2gUe4/u4ZHGcx+ulxchMGyHAC2QAoYChECC1DJSQBa1e8G3gcqsvi1PRDA VcHClz+BK0dsqiS1tMk/T3BVqpwITYA2Xjurdo2+hbJp0haGFZUfe3stqDtM/1CDf1Tr TKqWgA+4efBRqKxz3VEZb8/x5mkZL5NKcWwoVrnzIw2h+PtyNTsVU3gWi+crYMHoyLhO +D4bvYrBqLHAb44gD+wHJZ5BPaZ45LzgetQZ16Dq+M3v7FAb/q9mZZGSsl6whY4A/lHk mlp0vLkfgfn83WJsbhrXVt8zbo6sGk1FCWxz1M8hJdSH9Nld9ITGZz62ku+sQarLGeEU o32Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=sUnT3ujPcgcf9Q4OleidIWlUvOyf8yl/vIkF0lAkYrk=; b=CxwwIoGUbTccuzVNeJ7uWLHY6JvNxUsQL8d84/eogjzYrliMmRZKY62JxqMWn8QFgT yh3ZtlqqhOFHPUMhep4MwKKz7h81NClgzRx8L77I05GOkI6pb/KiiayxMFKyUeTN7zdM Q2jEhHjRBlw4IRp1dcZ5fC9kI02OFdNtTQlpVX1G8X4akkJ3rDmH03eXOtRw69cTu0Ac IJu442u+RVnG+IDkh3dZn4X/eic27nDU5XsSbsKMymHxzHFqacsyxK8DmipYNqhCOUjF HkFd6B8yHZX9qZehRMB1HeydoDzg/vHK0JzwI3TbZmtbeqDc5bM0YVOhrMgxpK065wK6 Uyug== X-Gm-Message-State: AO0yUKU0OAumg8Lg5bwjneI6vtDKqTEgy8tozh8No/TwVxT9Is0uEX1B Tnc0EQn1GzeOAFONzmsUftxZyQ== X-Google-Smtp-Source: AK7set9u2M4Qi4kBIcXcrX4ozbwOvbqVRpr2Rp4TSBRaPXCbLDLq9oo3O3+ONFwHhtgz41YClj+xHQ== X-Received: by 2002:a17:906:d154:b0:881:44e3:baae with SMTP id br20-20020a170906d15400b0088144e3baaemr4914519ejb.54.1676824690979; Sun, 19 Feb 2023 08:38:10 -0800 (PST) Received: from localhost.localdomain ([193.33.38.48]) by smtp.gmail.com with ESMTPSA id l13-20020a1709066b8d00b008cdb0628991sm647516ejr.57.2023.02.19.08.38.08 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 19 Feb 2023 08:38:09 -0800 (PST) From: Andrew Melnychenko To: jasowang@redhat.com, mst@redhat.com, pbonzini@redhat.com, marcandre.lureau@redhat.com, berrange@redhat.com, thuth@redhat.com, philmd@linaro.org, armbru@redhat.com, eblake@redhat.com, qemu-devel@nongnu.org, toke@redhat.com, mprivozn@redhat.com Cc: yuri.benditovich@daynix.com, yan@daynix.com Subject: [PATCH 4/5] ebpf_rss_helper: Added helper for eBPF RSS. Date: Sun, 19 Feb 2023 18:20:59 +0200 Message-Id: <20230219162100.174318-5-andrew@daynix.com> X-Mailer: git-send-email 2.39.1 In-Reply-To: <20230219162100.174318-1-andrew@daynix.com> References: <20230219162100.174318-1-andrew@daynix.com> MIME-Version: 1.0 Received-SPF: none client-ip=2a00:1450:4864:20::534; envelope-from=andrew@daynix.com; helo=mail-ed1-x534.google.com X-Spam_score_int: 14 X-Spam_score: 1.4 X-Spam_bar: + X-Spam_report: (1.4 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_SBL_CSS=3.335, SPF_HELO_NONE=0.001, SPF_NONE=0.001 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Helper program. Loads eBPF RSS program and maps and passes them through unix socket. Libvirt may launch this helper and pass eBPF fds to qemu virtio-net. Also, libbpf dependency for now is exclusively for Linux. Libbpf is used for eBPF RSS steering, which is supported only by Linux TAP. There is no reason yet to build eBPF loader and helper for non-Linux systems, even if libbpf is present. Signed-off-by: Andrew Melnychenko --- ebpf/qemu-ebpf-rss-helper.c | 132 ++++++++++++++++++++++++++++++++++++ meson.build | 37 ++++++---- 2 files changed, 156 insertions(+), 13 deletions(-) create mode 100644 ebpf/qemu-ebpf-rss-helper.c diff --git a/ebpf/qemu-ebpf-rss-helper.c b/ebpf/qemu-ebpf-rss-helper.c new file mode 100644 index 0000000000..348d26bcdd --- /dev/null +++ b/ebpf/qemu-ebpf-rss-helper.c @@ -0,0 +1,132 @@ +/* + * eBPF RSS Helper + * + * Developed by Daynix Computing LTD (http://www.daynix.com) + * + * Authors: + * Andrew Melnychenko + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Description: This is helper program for libvirtd. + * It loads eBPF RSS program and passes fds through unix socket. + * Built by meson, target - 'qemu-ebpf-rss-helper'. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ebpf_rss.h" + +#include "qemu-ebpf-rss-helper-stamp.h" + +void QEMU_EBPF_RSS_HELPER_STAMP(void) {} + +static int send_fds(int socket, int *fds, int n) +{ + struct msghdr msg = {}; + struct cmsghdr *cmsg = NULL; + char buf[CMSG_SPACE(n * sizeof(int))]; + char dummy_buffer = 0; + struct iovec io = { .iov_base = &dummy_buffer, + .iov_len = sizeof(dummy_buffer) }; + + memset(buf, 0, sizeof(buf)); + + msg.msg_iov = &io; + msg.msg_iovlen = 1; + msg.msg_control = buf; + msg.msg_controllen = sizeof(buf); + + cmsg = CMSG_FIRSTHDR(&msg); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + cmsg->cmsg_len = CMSG_LEN(n * sizeof(int)); + + memcpy(CMSG_DATA(cmsg), fds, n * sizeof(int)); + + return sendmsg(socket, &msg, 0); +} + +static void print_help_and_exit(const char *prog, int exitcode) +{ + fprintf(stderr, "%s - load eBPF RSS program for qemu and pass eBPF fds" + " through unix socket.\n", prog); + fprintf(stderr, "\t--fd , -f - unix socket file descriptor" + " used to pass eBPF fds.\n"); + fprintf(stderr, "\t--help, -h - this help.\n"); + exit(exitcode); +} + +int main(int argc, char **argv) +{ + char *fd_string = NULL; + int unix_fd = 0; + struct EBPFRSSContext ctx = {}; + int fds[EBPF_RSS_MAX_FDS] = {}; + int ret = -1; + + for (;;) { + int c; + static struct option long_options[] = { + {"help", no_argument, 0, 'h'}, + {"fd", required_argument, 0, 'f'}, + {0, 0, 0, 0} + }; + c = getopt_long(argc, argv, "hf:", + long_options, NULL); + + if (c == -1) { + break; + } + + switch (c) { + case 'f': + fd_string = optarg; + break; + case 'h': + default: + print_help_and_exit(argv[0], + c == 'h' ? EXIT_SUCCESS : EXIT_FAILURE); + } + } + + if (!fd_string) { + fprintf(stderr, "Unix file descriptor not present.\n"); + print_help_and_exit(argv[0], EXIT_FAILURE); + } + + unix_fd = atoi(fd_string); + + if (!unix_fd) { + fprintf(stderr, "Unix file descriptor is invalid.\n"); + return EXIT_FAILURE; + } + + ebpf_rss_init(&ctx); + if (!ebpf_rss_load(&ctx)) { + fprintf(stderr, "Can't load ebpf.\n"); + return EXIT_FAILURE; + } + fds[0] = ctx.program_fd; + fds[1] = ctx.map_configuration; + fds[2] = ctx.map_toeplitz_key; + fds[3] = ctx.map_indirections_table; + + ret = send_fds(unix_fd, fds, EBPF_RSS_MAX_FDS); + if (ret < 0) { + fprintf(stderr, "Issue while sending fds: %s.\n", strerror(errno)); + } + + ebpf_rss_unload(&ctx); + + return ret < 0 ? EXIT_FAILURE : EXIT_SUCCESS; +} + diff --git a/meson.build b/meson.build index b409912aed..6e6e2f3e40 100644 --- a/meson.build +++ b/meson.build @@ -1632,19 +1632,22 @@ elif get_option('vduse_blk_export').disabled() endif # libbpf -libbpf = dependency('libbpf', required: get_option('bpf'), method: 'pkg-config') -if libbpf.found() and not cc.links(''' - #include - int main(void) - { - bpf_object__destroy_skeleton(NULL); - return 0; - }''', dependencies: libbpf) - libbpf = not_found - if get_option('bpf').enabled() - error('libbpf skeleton test failed') - else - warning('libbpf skeleton test failed, disabling') +libbpf = not_found +if targetos == 'linux' + libbpf = dependency('libbpf', required: get_option('bpf'), method: 'pkg-config') + if libbpf.found() and not cc.links(''' + #include + int main(void) + { + bpf_object__destroy_skeleton(NULL); + return 0; + }''', dependencies: libbpf) + libbpf = not_found + if get_option('bpf').enabled() + error('libbpf skeleton test failed') + else + warning('libbpf skeleton test failed, disabling') + endif endif endif @@ -3646,6 +3649,14 @@ if have_tools dependencies: [authz, crypto, io, qom, qemuutil, libcap_ng, mpathpersist], install: true) + + if libbpf.found() + executable('qemu-ebpf-rss-helper', files( + 'ebpf/qemu-ebpf-rss-helper.c', 'ebpf/ebpf_rss.c'), + dependencies: [qemuutil, libbpf, glib], + install: true, + install_dir: get_option('libexecdir')) + endif endif if have_ivshmem From patchwork Sun Feb 19 16:21:00 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Melnichenko X-Patchwork-Id: 1744715 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=daynix-com.20210112.gappssmtp.com header.i=@daynix-com.20210112.gappssmtp.com header.a=rsa-sha256 header.s=20210112 header.b=PS9oxCc4; dkim-atps=neutral Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4PKWTv6hN3z23yR for ; Mon, 20 Feb 2023 03:39:15 +1100 (AEDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1pTmhe-0006QH-16; Sun, 19 Feb 2023 11:38:18 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pTmhc-0006PP-PJ for qemu-devel@nongnu.org; Sun, 19 Feb 2023 11:38:16 -0500 Received: from mail-ed1-x52f.google.com ([2a00:1450:4864:20::52f]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1pTmha-0006n4-Qt for qemu-devel@nongnu.org; Sun, 19 Feb 2023 11:38:16 -0500 Received: by mail-ed1-x52f.google.com with SMTP id er22so3215957edb.4 for ; Sun, 19 Feb 2023 08:38:14 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=daynix-com.20210112.gappssmtp.com; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=lVsMk5ChWyGsUbCE/J8puVv+yoyoDMi0ZC6FtH8BaZc=; b=PS9oxCc4GqQKGaKnReRr8kPCauzvsH2lIR/IVoSWsezzwXIDd0wDNO9seQ9luXQZqH 9gkJB8/iKhoj6c0VNGeHvFI26ZLvPTqTzZZ07vu+2ZhFY2a32xbY55dx+5lmprgzDeNH nTAUEoa0H7zBckxoN8sZJKRxnCgnBFXjVuHtKAKPh6RUuWYGyd1S+1dGVmwQhNzktTAh TBGZSC/MHE9+rqTIe30+bXgZx1xkffL9F0OP0NoVBGqf0b2q/KcpdkUwdu4PMQa0+lDi e8ELCZsvBhbeEYpfyKBC5j725+SUNuQrsBEsvQ2W8b/XjDlndkdbBmtD3c2LRGXyMRko H2nA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=lVsMk5ChWyGsUbCE/J8puVv+yoyoDMi0ZC6FtH8BaZc=; b=bvsdXo2eeBH6KdDMKedCwoHalXlL78a+l6vCdRTlQ9GLFQUWu9cabU4pqxL83QHACW EPiZVIBSEMR8vcCHJ8ko/Q5LdyBf3ULni3n/fDXrzm+lj/2U5EENpxkreIsnEFfG/CEV 2dnIUu0/ByKhVpp1oDyl5Dx0qCaJuD22faAPP55xETDM19q5+rB3hL5DdQXkRUk5S0rf oYkbdavHmjI42gqSxG3s8VwZrnQ3bZORC0C5+hwyUpN1JajvsQ4z2FznctI6DgEcF/77 SUnZrn1JrY+BjaMLK62mxxlV2VKSEtMF+yHCQkxfvLn9GL0bmFXoDdE0yI6wIQjVPJpm s2hQ== X-Gm-Message-State: AO0yUKX5mDTug3guXj9QpWZswECiD9weDM90nu9s6RWf+CRZc96Ipmr2 VbtVMTveeHs++TCb3YF6J6tKug== X-Google-Smtp-Source: AK7set/gdKPwFU3JS/V4Pm8VQLBTSn3jnmQX1iRWcIiCxe4lZFIUNwbnP04ifPJM1C74mO4mHoW0Qw== X-Received: by 2002:a17:906:af18:b0:88a:8e57:f063 with SMTP id lx24-20020a170906af1800b0088a8e57f063mr9134921ejb.62.1676824693622; Sun, 19 Feb 2023 08:38:13 -0800 (PST) Received: from localhost.localdomain ([193.33.38.48]) by smtp.gmail.com with ESMTPSA id l13-20020a1709066b8d00b008cdb0628991sm647516ejr.57.2023.02.19.08.38.11 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 19 Feb 2023 08:38:12 -0800 (PST) From: Andrew Melnychenko To: jasowang@redhat.com, mst@redhat.com, pbonzini@redhat.com, marcandre.lureau@redhat.com, berrange@redhat.com, thuth@redhat.com, philmd@linaro.org, armbru@redhat.com, eblake@redhat.com, qemu-devel@nongnu.org, toke@redhat.com, mprivozn@redhat.com Cc: yuri.benditovich@daynix.com, yan@daynix.com Subject: [PATCH 5/5] qmp: Added find-ebpf-rss-helper command. Date: Sun, 19 Feb 2023 18:21:00 +0200 Message-Id: <20230219162100.174318-6-andrew@daynix.com> X-Mailer: git-send-email 2.39.1 In-Reply-To: <20230219162100.174318-1-andrew@daynix.com> References: <20230219162100.174318-1-andrew@daynix.com> MIME-Version: 1.0 Received-SPF: none client-ip=2a00:1450:4864:20::52f; envelope-from=andrew@daynix.com; helo=mail-ed1-x52f.google.com X-Spam_score_int: 14 X-Spam_score: 1.4 X-Spam_bar: + X-Spam_report: (1.4 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_SBL_CSS=3.335, SPF_HELO_NONE=0.001, SPF_NONE=0.001 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org New qmp command to query ebpf helper. It's crucial that QEMU and helper are in sync. Technically helper should pass eBPF fds that QEMU may accept. And different QEMU's builds may have different eBPF programs. QEMU returns helper that should "fit" to virtio-net. QEMU would check the stamp of the helper to make sure that eBPF program is valid. Signed-off-by: Andrew Melnychenko --- monitor/qmp-cmds.c | 28 ++++++++++++++++++++++++++++ qapi/misc.json | 42 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+) diff --git a/monitor/qmp-cmds.c b/monitor/qmp-cmds.c index 859012aef4..2f91c34bbb 100644 --- a/monitor/qmp-cmds.c +++ b/monitor/qmp-cmds.c @@ -31,6 +31,7 @@ #include "hw/mem/memory-device.h" #include "hw/intc/intc.h" #include "hw/rdma/rdma.h" +#include "qemu-ebpf-rss-helper-stamp-utils.h" NameInfo *qmp_query_name(Error **errp) { @@ -202,3 +203,30 @@ static void __attribute__((__constructor__)) monitor_init_qmp_commands(void) qmp_marshal_qmp_capabilities, QCO_ALLOW_PRECONFIG, 0); } + +HelperPath *qmp_find_ebpf_rss_helper(bool has_path, + strList *path, Error **errp) +{ + HelperPath *ret = NULL; + char *helperbin = NULL; + + /* Look for helper in the suggested pathes */ + if (has_path) { + strList *str_list = NULL; + for (str_list = path; + str_list && !helperbin; + str_list = str_list->next) { + helperbin = qemu_check_suggested_ebpf_rss_helper(str_list->value); + } + } + + if (helperbin == NULL) { + helperbin = qemu_find_default_ebpf_rss_helper(); + } + + if (helperbin) { + ret = g_new0(HelperPath, 1); + ret->path = helperbin; + } + return ret; +} diff --git a/qapi/misc.json b/qapi/misc.json index 27ef5a2b20..1dfb3c132e 100644 --- a/qapi/misc.json +++ b/qapi/misc.json @@ -584,3 +584,45 @@ { 'event': 'VFU_CLIENT_HANGUP', 'data': { 'vfu-id': 'str', 'vfu-qom-path': 'str', 'dev-id': 'str', 'dev-qom-path': 'str' } } + +## +# @HelperPath: +# +# Name of the helper and binary location. +## +{ 'struct': 'HelperPath', + 'data': {'path': 'str'} } + +## +# @find-ebpf-rss-helper: +# +# Query helper paths to find qemu-ebpf-rss-helper. +# The qemu would check "the stamp" and +# returns the proper helper. +# It's possible to provide paths where to look for a helper. +# If the path is provided to a file - qemu would check the file for the stamp. +# If the path is provided to a directory - qemu would look for +# a file "qemu-ebpf-rss-helper" and check its stamp. +# +# Returns: path to the helper with a valid stamp. +# +# Note: Provided path arguments have the highest priority where to look +# for a helper. Then, default "helper directory" and then +# near the qemu binary. +# +# Since: 7.2 +# +# Example: +# +# -> { "execute": "find-ebpf-rss-helper", "arguments": { "path": "/opt/qemu_helpers/" } } +# <- { "return": [ +# { +# "path": "/usr/local/libexec/qemu-ebpf-rss-helper" +# } +# ] +# } +# +## +{ 'command': 'find-ebpf-rss-helper', + 'data': {'*path': ['str']}, + 'returns': 'HelperPath' }