xref: /openbmc/qemu/ebpf/ebpf_rss.c (revision a495eba0)
146627f41SAndrew Melnychenko /*
246627f41SAndrew Melnychenko  * eBPF RSS loader
346627f41SAndrew Melnychenko  *
446627f41SAndrew Melnychenko  * Developed by Daynix Computing LTD (http://www.daynix.com)
546627f41SAndrew Melnychenko  *
646627f41SAndrew Melnychenko  * Authors:
746627f41SAndrew Melnychenko  *  Andrew Melnychenko <andrew@daynix.com>
846627f41SAndrew Melnychenko  *  Yuri Benditovich <yuri.benditovich@daynix.com>
946627f41SAndrew Melnychenko  *
1046627f41SAndrew Melnychenko  * This work is licensed under the terms of the GNU GPL, version 2.  See
1146627f41SAndrew Melnychenko  * the COPYING file in the top-level directory.
1246627f41SAndrew Melnychenko  */
1346627f41SAndrew Melnychenko 
1446627f41SAndrew Melnychenko #include "qemu/osdep.h"
1546627f41SAndrew Melnychenko #include "qemu/error-report.h"
1646627f41SAndrew Melnychenko 
1746627f41SAndrew Melnychenko #include <bpf/libbpf.h>
1846627f41SAndrew Melnychenko #include <bpf/bpf.h>
1946627f41SAndrew Melnychenko 
2046627f41SAndrew Melnychenko #include "hw/virtio/virtio-net.h" /* VIRTIO_NET_RSS_MAX_TABLE_LEN */
2146627f41SAndrew Melnychenko 
2246627f41SAndrew Melnychenko #include "ebpf/ebpf_rss.h"
2346627f41SAndrew Melnychenko #include "ebpf/rss.bpf.skeleton.h"
2446627f41SAndrew Melnychenko #include "trace.h"
2546627f41SAndrew Melnychenko 
ebpf_rss_init(struct EBPFRSSContext * ctx)2646627f41SAndrew Melnychenko void ebpf_rss_init(struct EBPFRSSContext *ctx)
2746627f41SAndrew Melnychenko {
2846627f41SAndrew Melnychenko     if (ctx != NULL) {
2946627f41SAndrew Melnychenko         ctx->obj = NULL;
3046627f41SAndrew Melnychenko     }
3146627f41SAndrew Melnychenko }
3246627f41SAndrew Melnychenko 
ebpf_rss_is_loaded(struct EBPFRSSContext * ctx)3346627f41SAndrew Melnychenko bool ebpf_rss_is_loaded(struct EBPFRSSContext *ctx)
3446627f41SAndrew Melnychenko {
3546627f41SAndrew Melnychenko     return ctx != NULL && ctx->obj != NULL;
3646627f41SAndrew Melnychenko }
3746627f41SAndrew Melnychenko 
ebpf_rss_load(struct EBPFRSSContext * ctx)3846627f41SAndrew Melnychenko bool ebpf_rss_load(struct EBPFRSSContext *ctx)
3946627f41SAndrew Melnychenko {
4046627f41SAndrew Melnychenko     struct rss_bpf *rss_bpf_ctx;
4146627f41SAndrew Melnychenko 
4246627f41SAndrew Melnychenko     if (ctx == NULL) {
4346627f41SAndrew Melnychenko         return false;
4446627f41SAndrew Melnychenko     }
4546627f41SAndrew Melnychenko 
4646627f41SAndrew Melnychenko     rss_bpf_ctx = rss_bpf__open();
4746627f41SAndrew Melnychenko     if (rss_bpf_ctx == NULL) {
4846627f41SAndrew Melnychenko         trace_ebpf_error("eBPF RSS", "can not open eBPF RSS object");
4946627f41SAndrew Melnychenko         goto error;
5046627f41SAndrew Melnychenko     }
5146627f41SAndrew Melnychenko 
52*a495eba0SHaochen Tong     bpf_program__set_type(rss_bpf_ctx->progs.tun_rss_steering_prog, BPF_PROG_TYPE_SOCKET_FILTER);
5346627f41SAndrew Melnychenko 
5446627f41SAndrew Melnychenko     if (rss_bpf__load(rss_bpf_ctx)) {
5546627f41SAndrew Melnychenko         trace_ebpf_error("eBPF RSS", "can not load RSS program");
5646627f41SAndrew Melnychenko         goto error;
5746627f41SAndrew Melnychenko     }
5846627f41SAndrew Melnychenko 
5946627f41SAndrew Melnychenko     ctx->obj = rss_bpf_ctx;
6046627f41SAndrew Melnychenko     ctx->program_fd = bpf_program__fd(
6146627f41SAndrew Melnychenko             rss_bpf_ctx->progs.tun_rss_steering_prog);
6246627f41SAndrew Melnychenko     ctx->map_configuration = bpf_map__fd(
6346627f41SAndrew Melnychenko             rss_bpf_ctx->maps.tap_rss_map_configurations);
6446627f41SAndrew Melnychenko     ctx->map_indirections_table = bpf_map__fd(
6546627f41SAndrew Melnychenko             rss_bpf_ctx->maps.tap_rss_map_indirection_table);
6646627f41SAndrew Melnychenko     ctx->map_toeplitz_key = bpf_map__fd(
6746627f41SAndrew Melnychenko             rss_bpf_ctx->maps.tap_rss_map_toeplitz_key);
6846627f41SAndrew Melnychenko 
6946627f41SAndrew Melnychenko     return true;
7046627f41SAndrew Melnychenko error:
7146627f41SAndrew Melnychenko     rss_bpf__destroy(rss_bpf_ctx);
7246627f41SAndrew Melnychenko     ctx->obj = NULL;
7346627f41SAndrew Melnychenko 
7446627f41SAndrew Melnychenko     return false;
7546627f41SAndrew Melnychenko }
7646627f41SAndrew Melnychenko 
ebpf_rss_set_config(struct EBPFRSSContext * ctx,struct EBPFRSSConfig * config)7746627f41SAndrew Melnychenko static bool ebpf_rss_set_config(struct EBPFRSSContext *ctx,
7846627f41SAndrew Melnychenko                                 struct EBPFRSSConfig *config)
7946627f41SAndrew Melnychenko {
8046627f41SAndrew Melnychenko     uint32_t map_key = 0;
8146627f41SAndrew Melnychenko 
8246627f41SAndrew Melnychenko     if (!ebpf_rss_is_loaded(ctx)) {
8346627f41SAndrew Melnychenko         return false;
8446627f41SAndrew Melnychenko     }
8546627f41SAndrew Melnychenko     if (bpf_map_update_elem(ctx->map_configuration,
8646627f41SAndrew Melnychenko                             &map_key, config, 0) < 0) {
8746627f41SAndrew Melnychenko         return false;
8846627f41SAndrew Melnychenko     }
8946627f41SAndrew Melnychenko     return true;
9046627f41SAndrew Melnychenko }
9146627f41SAndrew Melnychenko 
ebpf_rss_set_indirections_table(struct EBPFRSSContext * ctx,uint16_t * indirections_table,size_t len)9246627f41SAndrew Melnychenko static bool ebpf_rss_set_indirections_table(struct EBPFRSSContext *ctx,
9346627f41SAndrew Melnychenko                                             uint16_t *indirections_table,
9446627f41SAndrew Melnychenko                                             size_t len)
9546627f41SAndrew Melnychenko {
9646627f41SAndrew Melnychenko     uint32_t i = 0;
9746627f41SAndrew Melnychenko 
9846627f41SAndrew Melnychenko     if (!ebpf_rss_is_loaded(ctx) || indirections_table == NULL ||
9946627f41SAndrew Melnychenko        len > VIRTIO_NET_RSS_MAX_TABLE_LEN) {
10046627f41SAndrew Melnychenko         return false;
10146627f41SAndrew Melnychenko     }
10246627f41SAndrew Melnychenko 
10346627f41SAndrew Melnychenko     for (; i < len; ++i) {
10446627f41SAndrew Melnychenko         if (bpf_map_update_elem(ctx->map_indirections_table, &i,
10546627f41SAndrew Melnychenko                                 indirections_table + i, 0) < 0) {
10646627f41SAndrew Melnychenko             return false;
10746627f41SAndrew Melnychenko         }
10846627f41SAndrew Melnychenko     }
10946627f41SAndrew Melnychenko     return true;
11046627f41SAndrew Melnychenko }
11146627f41SAndrew Melnychenko 
ebpf_rss_set_toepliz_key(struct EBPFRSSContext * ctx,uint8_t * toeplitz_key)11246627f41SAndrew Melnychenko static bool ebpf_rss_set_toepliz_key(struct EBPFRSSContext *ctx,
11346627f41SAndrew Melnychenko                                      uint8_t *toeplitz_key)
11446627f41SAndrew Melnychenko {
11546627f41SAndrew Melnychenko     uint32_t map_key = 0;
11646627f41SAndrew Melnychenko 
11746627f41SAndrew Melnychenko     /* prepare toeplitz key */
11846627f41SAndrew Melnychenko     uint8_t toe[VIRTIO_NET_RSS_MAX_KEY_SIZE] = {};
11946627f41SAndrew Melnychenko 
12046627f41SAndrew Melnychenko     if (!ebpf_rss_is_loaded(ctx) || toeplitz_key == NULL) {
12146627f41SAndrew Melnychenko         return false;
12246627f41SAndrew Melnychenko     }
12346627f41SAndrew Melnychenko     memcpy(toe, toeplitz_key, VIRTIO_NET_RSS_MAX_KEY_SIZE);
12446627f41SAndrew Melnychenko     *(uint32_t *)toe = ntohl(*(uint32_t *)toe);
12546627f41SAndrew Melnychenko 
12646627f41SAndrew Melnychenko     if (bpf_map_update_elem(ctx->map_toeplitz_key, &map_key, toe,
12746627f41SAndrew Melnychenko                             0) < 0) {
12846627f41SAndrew Melnychenko         return false;
12946627f41SAndrew Melnychenko     }
13046627f41SAndrew Melnychenko     return true;
13146627f41SAndrew Melnychenko }
13246627f41SAndrew Melnychenko 
ebpf_rss_set_all(struct EBPFRSSContext * ctx,struct EBPFRSSConfig * config,uint16_t * indirections_table,uint8_t * toeplitz_key)13346627f41SAndrew Melnychenko bool ebpf_rss_set_all(struct EBPFRSSContext *ctx, struct EBPFRSSConfig *config,
13446627f41SAndrew Melnychenko                       uint16_t *indirections_table, uint8_t *toeplitz_key)
13546627f41SAndrew Melnychenko {
13646627f41SAndrew Melnychenko     if (!ebpf_rss_is_loaded(ctx) || config == NULL ||
13746627f41SAndrew Melnychenko         indirections_table == NULL || toeplitz_key == NULL) {
13846627f41SAndrew Melnychenko         return false;
13946627f41SAndrew Melnychenko     }
14046627f41SAndrew Melnychenko 
14146627f41SAndrew Melnychenko     if (!ebpf_rss_set_config(ctx, config)) {
14246627f41SAndrew Melnychenko         return false;
14346627f41SAndrew Melnychenko     }
14446627f41SAndrew Melnychenko 
14546627f41SAndrew Melnychenko     if (!ebpf_rss_set_indirections_table(ctx, indirections_table,
14646627f41SAndrew Melnychenko                                       config->indirections_len)) {
14746627f41SAndrew Melnychenko         return false;
14846627f41SAndrew Melnychenko     }
14946627f41SAndrew Melnychenko 
15046627f41SAndrew Melnychenko     if (!ebpf_rss_set_toepliz_key(ctx, toeplitz_key)) {
15146627f41SAndrew Melnychenko         return false;
15246627f41SAndrew Melnychenko     }
15346627f41SAndrew Melnychenko 
15446627f41SAndrew Melnychenko     return true;
15546627f41SAndrew Melnychenko }
15646627f41SAndrew Melnychenko 
ebpf_rss_unload(struct EBPFRSSContext * ctx)15746627f41SAndrew Melnychenko void ebpf_rss_unload(struct EBPFRSSContext *ctx)
15846627f41SAndrew Melnychenko {
15946627f41SAndrew Melnychenko     if (!ebpf_rss_is_loaded(ctx)) {
16046627f41SAndrew Melnychenko         return;
16146627f41SAndrew Melnychenko     }
16246627f41SAndrew Melnychenko 
16346627f41SAndrew Melnychenko     rss_bpf__destroy(ctx->obj);
16446627f41SAndrew Melnychenko     ctx->obj = NULL;
16546627f41SAndrew Melnychenko }
166