xref: /openbmc/qemu/ebpf/ebpf_rss.c (revision 0524ea05)
1 /*
2  * eBPF RSS loader
3  *
4  * Developed by Daynix Computing LTD (http://www.daynix.com)
5  *
6  * Authors:
7  *  Andrew Melnychenko <andrew@daynix.com>
8  *  Yuri Benditovich <yuri.benditovich@daynix.com>
9  *
10  * This work is licensed under the terms of the GNU GPL, version 2.  See
11  * the COPYING file in the top-level directory.
12  */
13 
14 #include "qemu/osdep.h"
15 #include "qemu/error-report.h"
16 
17 #include <bpf/libbpf.h>
18 #include <bpf/bpf.h>
19 
20 #include "hw/virtio/virtio-net.h" /* VIRTIO_NET_RSS_MAX_TABLE_LEN */
21 
22 #include "ebpf/ebpf_rss.h"
23 #include "ebpf/rss.bpf.skeleton.h"
24 #include "trace.h"
25 
26 void ebpf_rss_init(struct EBPFRSSContext *ctx)
27 {
28     if (ctx != NULL) {
29         ctx->obj = NULL;
30         ctx->program_fd = -1;
31         ctx->map_configuration = -1;
32         ctx->map_toeplitz_key = -1;
33         ctx->map_indirections_table = -1;
34 
35         ctx->mmap_configuration = NULL;
36         ctx->mmap_toeplitz_key = NULL;
37         ctx->mmap_indirections_table = NULL;
38     }
39 }
40 
41 bool ebpf_rss_is_loaded(struct EBPFRSSContext *ctx)
42 {
43     return ctx != NULL && (ctx->obj != NULL || ctx->program_fd != -1);
44 }
45 
46 static bool ebpf_rss_mmap(struct EBPFRSSContext *ctx)
47 {
48     if (!ebpf_rss_is_loaded(ctx)) {
49         return false;
50     }
51 
52     ctx->mmap_configuration = mmap(NULL, qemu_real_host_page_size(),
53                                    PROT_READ | PROT_WRITE, MAP_SHARED,
54                                    ctx->map_configuration, 0);
55     if (ctx->mmap_configuration == MAP_FAILED) {
56         trace_ebpf_error("eBPF RSS", "can not mmap eBPF configuration array");
57         return false;
58     }
59     ctx->mmap_toeplitz_key = mmap(NULL, qemu_real_host_page_size(),
60                                    PROT_READ | PROT_WRITE, MAP_SHARED,
61                                    ctx->map_toeplitz_key, 0);
62     if (ctx->mmap_toeplitz_key == MAP_FAILED) {
63         trace_ebpf_error("eBPF RSS", "can not mmap eBPF toeplitz key");
64         goto toeplitz_fail;
65     }
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         trace_ebpf_error("eBPF RSS", "can not mmap eBPF indirection table");
71         goto indirection_fail;
72     }
73 
74     return true;
75 
76 indirection_fail:
77     munmap(ctx->mmap_toeplitz_key, qemu_real_host_page_size());
78     ctx->mmap_toeplitz_key = NULL;
79 toeplitz_fail:
80     munmap(ctx->mmap_configuration, qemu_real_host_page_size());
81     ctx->mmap_configuration = NULL;
82 
83     ctx->mmap_indirections_table = NULL;
84     return false;
85 }
86 
87 static void ebpf_rss_munmap(struct EBPFRSSContext *ctx)
88 {
89     if (!ebpf_rss_is_loaded(ctx)) {
90         return;
91     }
92 
93     munmap(ctx->mmap_indirections_table, qemu_real_host_page_size());
94     munmap(ctx->mmap_toeplitz_key, qemu_real_host_page_size());
95     munmap(ctx->mmap_configuration, qemu_real_host_page_size());
96 
97     ctx->mmap_configuration = NULL;
98     ctx->mmap_toeplitz_key = NULL;
99     ctx->mmap_indirections_table = NULL;
100 }
101 
102 bool ebpf_rss_load(struct EBPFRSSContext *ctx)
103 {
104     struct rss_bpf *rss_bpf_ctx;
105 
106     if (ebpf_rss_is_loaded(ctx)) {
107         return false;
108     }
109 
110     rss_bpf_ctx = rss_bpf__open();
111     if (rss_bpf_ctx == NULL) {
112         trace_ebpf_error("eBPF RSS", "can not open eBPF RSS object");
113         goto error;
114     }
115 
116     bpf_program__set_type(rss_bpf_ctx->progs.tun_rss_steering_prog, BPF_PROG_TYPE_SOCKET_FILTER);
117 
118     if (rss_bpf__load(rss_bpf_ctx)) {
119         trace_ebpf_error("eBPF RSS", "can not load RSS program");
120         goto error;
121     }
122 
123     ctx->obj = rss_bpf_ctx;
124     ctx->program_fd = bpf_program__fd(
125             rss_bpf_ctx->progs.tun_rss_steering_prog);
126     ctx->map_configuration = bpf_map__fd(
127             rss_bpf_ctx->maps.tap_rss_map_configurations);
128     ctx->map_indirections_table = bpf_map__fd(
129             rss_bpf_ctx->maps.tap_rss_map_indirection_table);
130     ctx->map_toeplitz_key = bpf_map__fd(
131             rss_bpf_ctx->maps.tap_rss_map_toeplitz_key);
132 
133     if (!ebpf_rss_mmap(ctx)) {
134         goto error;
135     }
136 
137     return true;
138 error:
139     rss_bpf__destroy(rss_bpf_ctx);
140     ctx->obj = NULL;
141     ctx->program_fd = -1;
142     ctx->map_configuration = -1;
143     ctx->map_toeplitz_key = -1;
144     ctx->map_indirections_table = -1;
145 
146     return false;
147 }
148 
149 bool ebpf_rss_load_fds(struct EBPFRSSContext *ctx, int program_fd,
150                        int config_fd, int toeplitz_fd, int table_fd)
151 {
152     if (ebpf_rss_is_loaded(ctx)) {
153         return false;
154     }
155 
156     if (program_fd < 0 || config_fd < 0 || toeplitz_fd < 0 || table_fd < 0) {
157         return false;
158     }
159 
160     ctx->program_fd = program_fd;
161     ctx->map_configuration = config_fd;
162     ctx->map_toeplitz_key = toeplitz_fd;
163     ctx->map_indirections_table = table_fd;
164 
165     if (!ebpf_rss_mmap(ctx)) {
166         ctx->program_fd = -1;
167         ctx->map_configuration = -1;
168         ctx->map_toeplitz_key = -1;
169         ctx->map_indirections_table = -1;
170         return false;
171     }
172 
173     return true;
174 }
175 
176 static bool ebpf_rss_set_config(struct EBPFRSSContext *ctx,
177                                 struct EBPFRSSConfig *config)
178 {
179     if (!ebpf_rss_is_loaded(ctx)) {
180         return false;
181     }
182 
183     memcpy(ctx->mmap_configuration, config, sizeof(*config));
184     return true;
185 }
186 
187 static bool ebpf_rss_set_indirections_table(struct EBPFRSSContext *ctx,
188                                             uint16_t *indirections_table,
189                                             size_t len)
190 {
191     if (!ebpf_rss_is_loaded(ctx) || indirections_table == NULL ||
192        len > VIRTIO_NET_RSS_MAX_TABLE_LEN) {
193         return false;
194     }
195 
196     memcpy(ctx->mmap_indirections_table, indirections_table,
197             sizeof(*indirections_table) * len);
198     return true;
199 }
200 
201 static bool ebpf_rss_set_toepliz_key(struct EBPFRSSContext *ctx,
202                                      uint8_t *toeplitz_key)
203 {
204     /* prepare toeplitz key */
205     uint8_t toe[VIRTIO_NET_RSS_MAX_KEY_SIZE] = {};
206 
207     if (!ebpf_rss_is_loaded(ctx) || toeplitz_key == NULL) {
208         return false;
209     }
210     memcpy(toe, toeplitz_key, VIRTIO_NET_RSS_MAX_KEY_SIZE);
211     *(uint32_t *)toe = ntohl(*(uint32_t *)toe);
212 
213     memcpy(ctx->mmap_toeplitz_key, toe, VIRTIO_NET_RSS_MAX_KEY_SIZE);
214     return true;
215 }
216 
217 bool ebpf_rss_set_all(struct EBPFRSSContext *ctx, struct EBPFRSSConfig *config,
218                       uint16_t *indirections_table, uint8_t *toeplitz_key)
219 {
220     if (!ebpf_rss_is_loaded(ctx) || config == NULL ||
221         indirections_table == NULL || toeplitz_key == NULL) {
222         return false;
223     }
224 
225     if (!ebpf_rss_set_config(ctx, config)) {
226         return false;
227     }
228 
229     if (!ebpf_rss_set_indirections_table(ctx, indirections_table,
230                                       config->indirections_len)) {
231         return false;
232     }
233 
234     if (!ebpf_rss_set_toepliz_key(ctx, toeplitz_key)) {
235         return false;
236     }
237 
238     return true;
239 }
240 
241 void ebpf_rss_unload(struct EBPFRSSContext *ctx)
242 {
243     if (!ebpf_rss_is_loaded(ctx)) {
244         return;
245     }
246 
247     ebpf_rss_munmap(ctx);
248 
249     if (ctx->obj) {
250         rss_bpf__destroy(ctx->obj);
251     } else {
252         close(ctx->program_fd);
253         close(ctx->map_configuration);
254         close(ctx->map_toeplitz_key);
255         close(ctx->map_indirections_table);
256     }
257 
258     ctx->obj = NULL;
259     ctx->program_fd = -1;
260     ctx->map_configuration = -1;
261     ctx->map_toeplitz_key = -1;
262     ctx->map_indirections_table = -1;
263 }
264