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"
30 void ebpf_rss_init(struct EBPFRSSContext
*ctx
)
35 ctx
->map_configuration
= -1;
36 ctx
->map_toeplitz_key
= -1;
37 ctx
->map_indirections_table
= -1;
39 ctx
->mmap_configuration
= NULL
;
40 ctx
->mmap_toeplitz_key
= NULL
;
41 ctx
->mmap_indirections_table
= NULL
;
45 bool ebpf_rss_is_loaded(struct EBPFRSSContext
*ctx
)
47 return ctx
!= NULL
&& (ctx
->obj
!= NULL
|| ctx
->program_fd
!= -1);
50 static bool ebpf_rss_mmap(struct EBPFRSSContext
*ctx
)
52 if (!ebpf_rss_is_loaded(ctx
)) {
56 ctx
->mmap_configuration
= mmap(NULL
, qemu_real_host_page_size(),
57 PROT_READ
| PROT_WRITE
, MAP_SHARED
,
58 ctx
->map_configuration
, 0);
59 if (ctx
->mmap_configuration
== MAP_FAILED
) {
60 trace_ebpf_error("eBPF RSS", "can not mmap eBPF configuration array");
63 ctx
->mmap_toeplitz_key
= mmap(NULL
, qemu_real_host_page_size(),
64 PROT_READ
| PROT_WRITE
, MAP_SHARED
,
65 ctx
->map_toeplitz_key
, 0);
66 if (ctx
->mmap_toeplitz_key
== MAP_FAILED
) {
67 trace_ebpf_error("eBPF RSS", "can not mmap eBPF toeplitz key");
70 ctx
->mmap_indirections_table
= mmap(NULL
, qemu_real_host_page_size(),
71 PROT_READ
| PROT_WRITE
, MAP_SHARED
,
72 ctx
->map_indirections_table
, 0);
73 if (ctx
->mmap_indirections_table
== MAP_FAILED
) {
74 trace_ebpf_error("eBPF RSS", "can not mmap eBPF indirection table");
75 goto indirection_fail
;
81 munmap(ctx
->mmap_toeplitz_key
, qemu_real_host_page_size());
82 ctx
->mmap_toeplitz_key
= NULL
;
84 munmap(ctx
->mmap_configuration
, qemu_real_host_page_size());
85 ctx
->mmap_configuration
= NULL
;
87 ctx
->mmap_indirections_table
= NULL
;
91 static void ebpf_rss_munmap(struct EBPFRSSContext
*ctx
)
93 if (!ebpf_rss_is_loaded(ctx
)) {
97 munmap(ctx
->mmap_indirections_table
, qemu_real_host_page_size());
98 munmap(ctx
->mmap_toeplitz_key
, qemu_real_host_page_size());
99 munmap(ctx
->mmap_configuration
, qemu_real_host_page_size());
101 ctx
->mmap_configuration
= NULL
;
102 ctx
->mmap_toeplitz_key
= NULL
;
103 ctx
->mmap_indirections_table
= NULL
;
106 bool ebpf_rss_load(struct EBPFRSSContext
*ctx
)
108 struct rss_bpf
*rss_bpf_ctx
;
110 if (ebpf_rss_is_loaded(ctx
)) {
114 rss_bpf_ctx
= rss_bpf__open();
115 if (rss_bpf_ctx
== NULL
) {
116 trace_ebpf_error("eBPF RSS", "can not open eBPF RSS object");
120 bpf_program__set_type(rss_bpf_ctx
->progs
.tun_rss_steering_prog
, BPF_PROG_TYPE_SOCKET_FILTER
);
122 if (rss_bpf__load(rss_bpf_ctx
)) {
123 trace_ebpf_error("eBPF RSS", "can not load RSS program");
127 ctx
->obj
= rss_bpf_ctx
;
128 ctx
->program_fd
= bpf_program__fd(
129 rss_bpf_ctx
->progs
.tun_rss_steering_prog
);
130 ctx
->map_configuration
= bpf_map__fd(
131 rss_bpf_ctx
->maps
.tap_rss_map_configurations
);
132 ctx
->map_indirections_table
= bpf_map__fd(
133 rss_bpf_ctx
->maps
.tap_rss_map_indirection_table
);
134 ctx
->map_toeplitz_key
= bpf_map__fd(
135 rss_bpf_ctx
->maps
.tap_rss_map_toeplitz_key
);
137 if (!ebpf_rss_mmap(ctx
)) {
143 rss_bpf__destroy(rss_bpf_ctx
);
145 ctx
->program_fd
= -1;
146 ctx
->map_configuration
= -1;
147 ctx
->map_toeplitz_key
= -1;
148 ctx
->map_indirections_table
= -1;
153 bool ebpf_rss_load_fds(struct EBPFRSSContext
*ctx
, int program_fd
,
154 int config_fd
, int toeplitz_fd
, int table_fd
)
156 if (ebpf_rss_is_loaded(ctx
)) {
160 if (program_fd
< 0 || config_fd
< 0 || toeplitz_fd
< 0 || table_fd
< 0) {
164 ctx
->program_fd
= program_fd
;
165 ctx
->map_configuration
= config_fd
;
166 ctx
->map_toeplitz_key
= toeplitz_fd
;
167 ctx
->map_indirections_table
= table_fd
;
169 if (!ebpf_rss_mmap(ctx
)) {
170 ctx
->program_fd
= -1;
171 ctx
->map_configuration
= -1;
172 ctx
->map_toeplitz_key
= -1;
173 ctx
->map_indirections_table
= -1;
180 static bool ebpf_rss_set_config(struct EBPFRSSContext
*ctx
,
181 struct EBPFRSSConfig
*config
)
183 if (!ebpf_rss_is_loaded(ctx
)) {
187 memcpy(ctx
->mmap_configuration
, config
, sizeof(*config
));
191 static bool ebpf_rss_set_indirections_table(struct EBPFRSSContext
*ctx
,
192 uint16_t *indirections_table
,
195 char *cursor
= ctx
->mmap_indirections_table
;
197 if (!ebpf_rss_is_loaded(ctx
) || indirections_table
== NULL
||
198 len
> VIRTIO_NET_RSS_MAX_TABLE_LEN
) {
202 for (size_t i
= 0; i
< len
; i
++) {
203 *(uint16_t *)cursor
= indirections_table
[i
];
210 static bool ebpf_rss_set_toepliz_key(struct EBPFRSSContext
*ctx
,
211 uint8_t *toeplitz_key
)
213 /* prepare toeplitz key */
214 uint8_t toe
[VIRTIO_NET_RSS_MAX_KEY_SIZE
] = {};
216 if (!ebpf_rss_is_loaded(ctx
) || toeplitz_key
== NULL
) {
219 memcpy(toe
, toeplitz_key
, VIRTIO_NET_RSS_MAX_KEY_SIZE
);
220 *(uint32_t *)toe
= ntohl(*(uint32_t *)toe
);
222 memcpy(ctx
->mmap_toeplitz_key
, toe
, VIRTIO_NET_RSS_MAX_KEY_SIZE
);
226 bool ebpf_rss_set_all(struct EBPFRSSContext
*ctx
, struct EBPFRSSConfig
*config
,
227 uint16_t *indirections_table
, uint8_t *toeplitz_key
)
229 if (!ebpf_rss_is_loaded(ctx
) || config
== NULL
||
230 indirections_table
== NULL
|| toeplitz_key
== NULL
) {
234 if (!ebpf_rss_set_config(ctx
, config
)) {
238 if (!ebpf_rss_set_indirections_table(ctx
, indirections_table
,
239 config
->indirections_len
)) {
243 if (!ebpf_rss_set_toepliz_key(ctx
, toeplitz_key
)) {
250 void ebpf_rss_unload(struct EBPFRSSContext
*ctx
)
252 if (!ebpf_rss_is_loaded(ctx
)) {
256 ebpf_rss_munmap(ctx
);
259 rss_bpf__destroy(ctx
->obj
);
261 close(ctx
->program_fd
);
262 close(ctx
->map_configuration
);
263 close(ctx
->map_toeplitz_key
);
264 close(ctx
->map_indirections_table
);
268 ctx
->program_fd
= -1;
269 ctx
->map_configuration
= -1;
270 ctx
->map_toeplitz_key
= -1;
271 ctx
->map_indirections_table
= -1;
274 ebpf_binary_init(EBPF_PROGRAMID_RSS
, rss_bpf__elf_bytes
)