4 * Developed by Daynix Computing LTD (http://www.daynix.com)
7 * Andrew Melnychenko <andrew@daynix.com>
8 * Yuri Benditovich <yuri.benditovich@daynix.com>
10 * This work is licensed under the terms of the GNU GPL, version 2. See
11 * the COPYING file in the top-level directory.
14 #include "qemu/osdep.h"
15 #include "qemu/error-report.h"
16 #include "qapi/qapi-types-misc.h"
17 #include "qapi/qapi-commands-ebpf.h"
19 #include <bpf/libbpf.h>
22 #include "hw/virtio/virtio-net.h" /* VIRTIO_NET_RSS_MAX_TABLE_LEN */
24 #include "ebpf/ebpf_rss.h"
25 #include "ebpf/rss.bpf.skeleton.h"
26 #include "ebpf/ebpf.h"
28 void ebpf_rss_init(struct EBPFRSSContext
*ctx
)
33 ctx
->map_configuration
= -1;
34 ctx
->map_toeplitz_key
= -1;
35 ctx
->map_indirections_table
= -1;
37 ctx
->mmap_configuration
= NULL
;
38 ctx
->mmap_toeplitz_key
= NULL
;
39 ctx
->mmap_indirections_table
= NULL
;
43 bool ebpf_rss_is_loaded(struct EBPFRSSContext
*ctx
)
45 return ctx
!= NULL
&& (ctx
->obj
!= NULL
|| ctx
->program_fd
!= -1);
48 static bool ebpf_rss_mmap(struct EBPFRSSContext
*ctx
)
50 if (!ebpf_rss_is_loaded(ctx
)) {
54 ctx
->mmap_configuration
= mmap(NULL
, qemu_real_host_page_size(),
55 PROT_READ
| PROT_WRITE
, MAP_SHARED
,
56 ctx
->map_configuration
, 0);
57 if (ctx
->mmap_configuration
== MAP_FAILED
) {
60 ctx
->mmap_toeplitz_key
= mmap(NULL
, qemu_real_host_page_size(),
61 PROT_READ
| PROT_WRITE
, MAP_SHARED
,
62 ctx
->map_toeplitz_key
, 0);
63 if (ctx
->mmap_toeplitz_key
== MAP_FAILED
) {
66 ctx
->mmap_indirections_table
= mmap(NULL
, qemu_real_host_page_size(),
67 PROT_READ
| PROT_WRITE
, MAP_SHARED
,
68 ctx
->map_indirections_table
, 0);
69 if (ctx
->mmap_indirections_table
== MAP_FAILED
) {
70 goto indirection_fail
;
76 munmap(ctx
->mmap_toeplitz_key
, qemu_real_host_page_size());
77 ctx
->mmap_toeplitz_key
= NULL
;
79 munmap(ctx
->mmap_configuration
, qemu_real_host_page_size());
80 ctx
->mmap_configuration
= NULL
;
82 ctx
->mmap_indirections_table
= NULL
;
86 static void ebpf_rss_munmap(struct EBPFRSSContext
*ctx
)
88 if (!ebpf_rss_is_loaded(ctx
)) {
92 munmap(ctx
->mmap_indirections_table
, qemu_real_host_page_size());
93 munmap(ctx
->mmap_toeplitz_key
, qemu_real_host_page_size());
94 munmap(ctx
->mmap_configuration
, qemu_real_host_page_size());
96 ctx
->mmap_configuration
= NULL
;
97 ctx
->mmap_toeplitz_key
= NULL
;
98 ctx
->mmap_indirections_table
= NULL
;
101 bool ebpf_rss_load(struct EBPFRSSContext
*ctx
)
103 struct rss_bpf
*rss_bpf_ctx
;
105 if (ebpf_rss_is_loaded(ctx
)) {
109 rss_bpf_ctx
= rss_bpf__open();
110 if (rss_bpf_ctx
== NULL
) {
114 bpf_program__set_type(rss_bpf_ctx
->progs
.tun_rss_steering_prog
, BPF_PROG_TYPE_SOCKET_FILTER
);
116 if (rss_bpf__load(rss_bpf_ctx
)) {
120 ctx
->obj
= rss_bpf_ctx
;
121 ctx
->program_fd
= bpf_program__fd(
122 rss_bpf_ctx
->progs
.tun_rss_steering_prog
);
123 ctx
->map_configuration
= bpf_map__fd(
124 rss_bpf_ctx
->maps
.tap_rss_map_configurations
);
125 ctx
->map_indirections_table
= bpf_map__fd(
126 rss_bpf_ctx
->maps
.tap_rss_map_indirection_table
);
127 ctx
->map_toeplitz_key
= bpf_map__fd(
128 rss_bpf_ctx
->maps
.tap_rss_map_toeplitz_key
);
130 if (!ebpf_rss_mmap(ctx
)) {
136 rss_bpf__destroy(rss_bpf_ctx
);
138 ctx
->program_fd
= -1;
139 ctx
->map_configuration
= -1;
140 ctx
->map_toeplitz_key
= -1;
141 ctx
->map_indirections_table
= -1;
146 bool ebpf_rss_load_fds(struct EBPFRSSContext
*ctx
, int program_fd
,
147 int config_fd
, int toeplitz_fd
, int table_fd
)
149 if (ebpf_rss_is_loaded(ctx
)) {
153 if (program_fd
< 0 || config_fd
< 0 || toeplitz_fd
< 0 || table_fd
< 0) {
157 ctx
->program_fd
= program_fd
;
158 ctx
->map_configuration
= config_fd
;
159 ctx
->map_toeplitz_key
= toeplitz_fd
;
160 ctx
->map_indirections_table
= table_fd
;
162 if (!ebpf_rss_mmap(ctx
)) {
163 ctx
->program_fd
= -1;
164 ctx
->map_configuration
= -1;
165 ctx
->map_toeplitz_key
= -1;
166 ctx
->map_indirections_table
= -1;
173 static bool ebpf_rss_set_config(struct EBPFRSSContext
*ctx
,
174 struct EBPFRSSConfig
*config
)
176 if (!ebpf_rss_is_loaded(ctx
)) {
180 memcpy(ctx
->mmap_configuration
, config
, sizeof(*config
));
184 static bool ebpf_rss_set_indirections_table(struct EBPFRSSContext
*ctx
,
185 uint16_t *indirections_table
,
188 if (!ebpf_rss_is_loaded(ctx
) || indirections_table
== NULL
||
189 len
> VIRTIO_NET_RSS_MAX_TABLE_LEN
) {
193 memcpy(ctx
->mmap_indirections_table
, indirections_table
,
194 sizeof(*indirections_table
) * len
);
198 static bool ebpf_rss_set_toepliz_key(struct EBPFRSSContext
*ctx
,
199 uint8_t *toeplitz_key
)
201 /* prepare toeplitz key */
202 uint8_t toe
[VIRTIO_NET_RSS_MAX_KEY_SIZE
] = {};
204 if (!ebpf_rss_is_loaded(ctx
) || toeplitz_key
== NULL
) {
207 memcpy(toe
, toeplitz_key
, VIRTIO_NET_RSS_MAX_KEY_SIZE
);
208 *(uint32_t *)toe
= ntohl(*(uint32_t *)toe
);
210 memcpy(ctx
->mmap_toeplitz_key
, toe
, VIRTIO_NET_RSS_MAX_KEY_SIZE
);
214 bool ebpf_rss_set_all(struct EBPFRSSContext
*ctx
, struct EBPFRSSConfig
*config
,
215 uint16_t *indirections_table
, uint8_t *toeplitz_key
)
217 if (!ebpf_rss_is_loaded(ctx
) || config
== NULL
||
218 indirections_table
== NULL
|| toeplitz_key
== NULL
) {
222 if (!ebpf_rss_set_config(ctx
, config
)) {
226 if (!ebpf_rss_set_indirections_table(ctx
, indirections_table
,
227 config
->indirections_len
)) {
231 if (!ebpf_rss_set_toepliz_key(ctx
, toeplitz_key
)) {
238 void ebpf_rss_unload(struct EBPFRSSContext
*ctx
)
240 if (!ebpf_rss_is_loaded(ctx
)) {
244 ebpf_rss_munmap(ctx
);
247 rss_bpf__destroy(ctx
->obj
);
249 close(ctx
->program_fd
);
250 close(ctx
->map_configuration
);
251 close(ctx
->map_toeplitz_key
);
252 close(ctx
->map_indirections_table
);
256 ctx
->program_fd
= -1;
257 ctx
->map_configuration
= -1;
258 ctx
->map_toeplitz_key
= -1;
259 ctx
->map_indirections_table
= -1;
262 ebpf_binary_init(EBPF_PROGRAMID_RSS
, rss_bpf__elf_bytes
)