Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2018 Intel Corporation
3 : : */
4 : :
5 : : #include <stdio.h>
6 : : #include <stdint.h>
7 : :
8 : : #include <eal_export.h>
9 : : #include <rte_common.h>
10 : : #include <rte_log.h>
11 : : #include <rte_debug.h>
12 : : #include <rte_byteorder.h>
13 : : #include <rte_errno.h>
14 : :
15 : : #include "bpf_impl.h"
16 : :
17 : : #define BPF_JMP_UNC(ins) ((ins) += (ins)->off)
18 : :
19 : : #define BPF_JMP_CND_REG(reg, ins, op, type) \
20 : : ((ins) += \
21 : : ((type)(reg)[(ins)->dst_reg] op (type)(reg)[(ins)->src_reg]) ? \
22 : : (ins)->off : 0)
23 : :
24 : : #define BPF_JMP_CND_IMM(reg, ins, op, type) \
25 : : ((ins) += \
26 : : ((type)(reg)[(ins)->dst_reg] op (type)(ins)->imm) ? \
27 : : (ins)->off : 0)
28 : :
29 : : #define BPF_NEG_ALU(reg, ins, type) \
30 : : ((reg)[(ins)->dst_reg] = (type)(-(reg)[(ins)->dst_reg]))
31 : :
32 : : #define EBPF_MOV_ALU_REG(reg, ins, type) \
33 : : ((reg)[(ins)->dst_reg] = (type)(reg)[(ins)->src_reg])
34 : :
35 : : #define BPF_OP_ALU_REG(reg, ins, op, type) \
36 : : ((reg)[(ins)->dst_reg] = \
37 : : (type)(reg)[(ins)->dst_reg] op (type)(reg)[(ins)->src_reg])
38 : :
39 : : #define EBPF_MOV_ALU_IMM(reg, ins, type) \
40 : : ((reg)[(ins)->dst_reg] = (type)(ins)->imm)
41 : :
42 : : #define BPF_OP_ALU_IMM(reg, ins, op, type) \
43 : : ((reg)[(ins)->dst_reg] = \
44 : : (type)(reg)[(ins)->dst_reg] op (type)(ins)->imm)
45 : :
46 : : #define BPF_DIV_ZERO_CHECK(bpf, reg, ins, type) do { \
47 : : if ((type)(reg)[(ins)->src_reg] == 0) { \
48 : : RTE_BPF_LOG_LINE(ERR, \
49 : : "%s(%p): division by 0 at pc: %#zx;", \
50 : : __func__, bpf, \
51 : : (uintptr_t)(ins) - (uintptr_t)(bpf)->prm.raw.ins); \
52 : : return 0; \
53 : : } \
54 : : } while (0)
55 : :
56 : : #define BPF_LD_REG(reg, ins, type) \
57 : : ((reg)[(ins)->dst_reg] = \
58 : : *(type *)(uintptr_t)((reg)[(ins)->src_reg] + (ins)->off))
59 : :
60 : : #define BPF_ST_IMM(reg, ins, type) \
61 : : (*(type *)(uintptr_t)((reg)[(ins)->dst_reg] + (ins)->off) = \
62 : : (type)(ins)->imm)
63 : :
64 : : #define BPF_ST_REG(reg, ins, type) \
65 : : (*(type *)(uintptr_t)((reg)[(ins)->dst_reg] + (ins)->off) = \
66 : : (type)(reg)[(ins)->src_reg])
67 : :
68 : : #define BPF_ST_ATOMIC_REG(reg, ins, tp) do { \
69 : : switch (ins->imm) { \
70 : : case BPF_ATOMIC_ADD: \
71 : : rte_atomic##tp##_add((rte_atomic##tp##_t *) \
72 : : (uintptr_t)((reg)[(ins)->dst_reg] + (ins)->off), \
73 : : (reg)[(ins)->src_reg]); \
74 : : break; \
75 : : case BPF_ATOMIC_XCHG: \
76 : : (reg)[(ins)->src_reg] = rte_atomic##tp##_exchange((uint##tp##_t *) \
77 : : (uintptr_t)((reg)[(ins)->dst_reg] + (ins)->off), \
78 : : (reg)[(ins)->src_reg]); \
79 : : break; \
80 : : default: \
81 : : /* this should be caught by validator and never reach here */ \
82 : : RTE_BPF_LOG_LINE(ERR, \
83 : : "%s(%p): unsupported atomic operation at pc: %#zx;", \
84 : : __func__, bpf, \
85 : : (uintptr_t)(ins) - (uintptr_t)(bpf)->prm.raw.ins); \
86 : : return 0; \
87 : : } \
88 : : } while (0)
89 : :
90 : : /* BPF_LD | BPF_ABS/BPF_IND */
91 : :
92 : : #define NOP(x) (x)
93 : :
94 : : #define BPF_LD_ABS(bpf, reg, ins, type, op) do { \
95 : : const type *p = bpf_ld_mbuf(bpf, reg, ins, (ins)->imm, sizeof(type)); \
96 : : if (p == NULL) \
97 : : return 0; \
98 : : reg[EBPF_REG_0] = op(p[0]); \
99 : : } while (0)
100 : :
101 : : #define BPF_LD_IND(bpf, reg, ins, type, op) do { \
102 : : uint32_t ofs = reg[ins->src_reg] + (ins)->imm; \
103 : : const type *p = bpf_ld_mbuf(bpf, reg, ins, ofs, sizeof(type)); \
104 : : if (p == NULL) \
105 : : return 0; \
106 : : reg[EBPF_REG_0] = op(p[0]); \
107 : : } while (0)
108 : :
109 : :
110 : : static inline void
111 : 5 : bpf_alu_be(uint64_t reg[EBPF_REG_NUM], const struct ebpf_insn *ins)
112 : : {
113 : : uint64_t *v;
114 : :
115 : 5 : v = reg + ins->dst_reg;
116 [ + + + - ]: 5 : switch (ins->imm) {
117 : 1 : case 16:
118 [ - + ]: 1 : *v = rte_cpu_to_be_16(*v);
119 : 1 : break;
120 : 3 : case 32:
121 [ - + ]: 3 : *v = rte_cpu_to_be_32(*v);
122 : 3 : break;
123 : 1 : case 64:
124 [ - + ]: 1 : *v = rte_cpu_to_be_64(*v);
125 : 1 : break;
126 : : }
127 : 5 : }
128 : :
129 : : static inline void
130 : : bpf_alu_le(uint64_t reg[EBPF_REG_NUM], const struct ebpf_insn *ins)
131 : : {
132 : : uint64_t *v;
133 : :
134 : : v = reg + ins->dst_reg;
135 : : switch (ins->imm) {
136 : : case 16:
137 : : *v = rte_cpu_to_le_16(*v);
138 : : break;
139 : : case 32:
140 : : *v = rte_cpu_to_le_32(*v);
141 : : break;
142 : : case 64:
143 : : *v = rte_cpu_to_le_64(*v);
144 : : break;
145 : : }
146 : : }
147 : :
148 : : static inline const void *
149 : 21 : bpf_ld_mbuf(const struct rte_bpf *bpf, uint64_t reg[EBPF_REG_NUM],
150 : : const struct ebpf_insn *ins, uint32_t off, uint32_t len)
151 : : {
152 : : const struct rte_mbuf *mb;
153 : : const void *p;
154 : :
155 [ + + ]: 21 : mb = (const struct rte_mbuf *)(uintptr_t)reg[EBPF_REG_6];
156 : : p = rte_pktmbuf_read(mb, off, len, reg + EBPF_REG_0);
157 [ + + ]: 21 : if (p == NULL)
158 : 1 : RTE_BPF_LOG_LINE(DEBUG, "%s(bpf=%p, mbuf=%p, ofs=%u, len=%u): "
159 : : "load beyond packet boundary at pc: %#zx;",
160 : : __func__, bpf, mb, off, len,
161 : : (uintptr_t)(ins) - (uintptr_t)(bpf)->prm.raw.ins);
162 : 21 : return p;
163 : : }
164 : :
165 : : static inline uint64_t
166 : 28 : bpf_exec(const struct rte_bpf *bpf, uint64_t reg[EBPF_REG_NUM])
167 : : {
168 : : const struct ebpf_insn *ins;
169 : :
170 : 380 : for (ins = bpf->prm.raw.ins; ; ins++) {
171 [ - - + - : 380 : switch (ins->code) {
+ - + + +
- + - + +
+ + + - +
+ + - + +
+ + + + +
+ + + + -
+ + + + +
- + - + +
+ + - + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
- - - - -
- + + + +
- - - + +
- - - + +
+ - + ]
172 : : /* 32 bit ALU IMM operations */
173 : 0 : case (BPF_ALU | BPF_ADD | BPF_K):
174 : 0 : BPF_OP_ALU_IMM(reg, ins, +, uint32_t);
175 : 0 : break;
176 : 0 : case (BPF_ALU | BPF_SUB | BPF_K):
177 : 0 : BPF_OP_ALU_IMM(reg, ins, -, uint32_t);
178 : 0 : break;
179 : 11 : case (BPF_ALU | BPF_AND | BPF_K):
180 : 11 : BPF_OP_ALU_IMM(reg, ins, &, uint32_t);
181 : 11 : break;
182 : 0 : case (BPF_ALU | BPF_OR | BPF_K):
183 : 0 : BPF_OP_ALU_IMM(reg, ins, |, uint32_t);
184 : 0 : break;
185 : 4 : case (BPF_ALU | BPF_LSH | BPF_K):
186 : 4 : BPF_OP_ALU_IMM(reg, ins, <<, uint32_t);
187 : 4 : break;
188 : 0 : case (BPF_ALU | BPF_RSH | BPF_K):
189 : 0 : BPF_OP_ALU_IMM(reg, ins, >>, uint32_t);
190 : 0 : break;
191 : 1 : case (BPF_ALU | BPF_XOR | BPF_K):
192 : 1 : BPF_OP_ALU_IMM(reg, ins, ^, uint32_t);
193 : 1 : break;
194 : 1 : case (BPF_ALU | BPF_MUL | BPF_K):
195 : 1 : BPF_OP_ALU_IMM(reg, ins, *, uint32_t);
196 : 1 : break;
197 : 1 : case (BPF_ALU | BPF_DIV | BPF_K):
198 : 1 : BPF_OP_ALU_IMM(reg, ins, /, uint32_t);
199 : 1 : break;
200 : 0 : case (BPF_ALU | BPF_MOD | BPF_K):
201 : 0 : BPF_OP_ALU_IMM(reg, ins, %, uint32_t);
202 : 0 : break;
203 : 14 : case (BPF_ALU | EBPF_MOV | BPF_K):
204 : 14 : EBPF_MOV_ALU_IMM(reg, ins, uint32_t);
205 : 14 : break;
206 : : /* 32 bit ALU REG operations */
207 : 0 : case (BPF_ALU | BPF_ADD | BPF_X):
208 : 0 : BPF_OP_ALU_REG(reg, ins, +, uint32_t);
209 : 0 : break;
210 : 1 : case (BPF_ALU | BPF_SUB | BPF_X):
211 : 1 : BPF_OP_ALU_REG(reg, ins, -, uint32_t);
212 : 1 : break;
213 : 1 : case (BPF_ALU | BPF_AND | BPF_X):
214 : 1 : BPF_OP_ALU_REG(reg, ins, &, uint32_t);
215 : 1 : break;
216 : 1 : case (BPF_ALU | BPF_OR | BPF_X):
217 : 1 : BPF_OP_ALU_REG(reg, ins, |, uint32_t);
218 : 1 : break;
219 : 1 : case (BPF_ALU | BPF_LSH | BPF_X):
220 : 1 : BPF_OP_ALU_REG(reg, ins, <<, uint32_t);
221 : 1 : break;
222 : 1 : case (BPF_ALU | BPF_RSH | BPF_X):
223 : 1 : BPF_OP_ALU_REG(reg, ins, >>, uint32_t);
224 : 1 : break;
225 : 0 : case (BPF_ALU | BPF_XOR | BPF_X):
226 : 0 : BPF_OP_ALU_REG(reg, ins, ^, uint32_t);
227 : 0 : break;
228 : 1 : case (BPF_ALU | BPF_MUL | BPF_X):
229 : 1 : BPF_OP_ALU_REG(reg, ins, *, uint32_t);
230 : 1 : break;
231 : 1 : case (BPF_ALU | BPF_DIV | BPF_X):
232 [ + - ]: 1 : BPF_DIV_ZERO_CHECK(bpf, reg, ins, uint32_t);
233 : 0 : BPF_OP_ALU_REG(reg, ins, /, uint32_t);
234 : 0 : break;
235 : 1 : case (BPF_ALU | BPF_MOD | BPF_X):
236 [ - + ]: 1 : BPF_DIV_ZERO_CHECK(bpf, reg, ins, uint32_t);
237 : 1 : BPF_OP_ALU_REG(reg, ins, %, uint32_t);
238 : 1 : break;
239 : 0 : case (BPF_ALU | EBPF_MOV | BPF_X):
240 : 0 : EBPF_MOV_ALU_REG(reg, ins, uint32_t);
241 : 0 : break;
242 : 1 : case (BPF_ALU | BPF_NEG):
243 : 1 : BPF_NEG_ALU(reg, ins, uint32_t);
244 : 1 : break;
245 : 5 : case (BPF_ALU | EBPF_END | EBPF_TO_BE):
246 : 5 : bpf_alu_be(reg, ins);
247 : 5 : break;
248 : : case (BPF_ALU | EBPF_END | EBPF_TO_LE):
249 : : bpf_alu_le(reg, ins);
250 : : break;
251 : : /* 64 bit ALU IMM operations */
252 : 6 : case (EBPF_ALU64 | BPF_ADD | BPF_K):
253 : 6 : BPF_OP_ALU_IMM(reg, ins, +, uint64_t);
254 : 6 : break;
255 : 2 : case (EBPF_ALU64 | BPF_SUB | BPF_K):
256 : 2 : BPF_OP_ALU_IMM(reg, ins, -, uint64_t);
257 : 2 : break;
258 : 1 : case (EBPF_ALU64 | BPF_AND | BPF_K):
259 : 1 : BPF_OP_ALU_IMM(reg, ins, &, uint64_t);
260 : 1 : break;
261 : 9 : case (EBPF_ALU64 | BPF_OR | BPF_K):
262 : 9 : BPF_OP_ALU_IMM(reg, ins, |, uint64_t);
263 : 9 : break;
264 : 2 : case (EBPF_ALU64 | BPF_LSH | BPF_K):
265 : 2 : BPF_OP_ALU_IMM(reg, ins, <<, uint64_t);
266 : 2 : break;
267 : 4 : case (EBPF_ALU64 | BPF_RSH | BPF_K):
268 : 4 : BPF_OP_ALU_IMM(reg, ins, >>, uint64_t);
269 : 4 : break;
270 : 1 : case (EBPF_ALU64 | EBPF_ARSH | BPF_K):
271 : 1 : BPF_OP_ALU_IMM(reg, ins, >>, int64_t);
272 : 1 : break;
273 : 1 : case (EBPF_ALU64 | BPF_XOR | BPF_K):
274 : 1 : BPF_OP_ALU_IMM(reg, ins, ^, uint64_t);
275 : 1 : break;
276 : 1 : case (EBPF_ALU64 | BPF_MUL | BPF_K):
277 : 1 : BPF_OP_ALU_IMM(reg, ins, *, uint64_t);
278 : 1 : break;
279 : 0 : case (EBPF_ALU64 | BPF_DIV | BPF_K):
280 : 0 : BPF_OP_ALU_IMM(reg, ins, /, uint64_t);
281 : 0 : break;
282 : 1 : case (EBPF_ALU64 | BPF_MOD | BPF_K):
283 : 1 : BPF_OP_ALU_IMM(reg, ins, %, uint64_t);
284 : 1 : break;
285 : 16 : case (EBPF_ALU64 | EBPF_MOV | BPF_K):
286 : 16 : EBPF_MOV_ALU_IMM(reg, ins, uint64_t);
287 : 16 : break;
288 : : /* 64 bit ALU REG operations */
289 : 24 : case (EBPF_ALU64 | BPF_ADD | BPF_X):
290 : 24 : BPF_OP_ALU_REG(reg, ins, +, uint64_t);
291 : 24 : break;
292 : 1 : case (EBPF_ALU64 | BPF_SUB | BPF_X):
293 : 1 : BPF_OP_ALU_REG(reg, ins, -, uint64_t);
294 : 1 : break;
295 : 1 : case (EBPF_ALU64 | BPF_AND | BPF_X):
296 : 1 : BPF_OP_ALU_REG(reg, ins, &, uint64_t);
297 : 1 : break;
298 : 0 : case (EBPF_ALU64 | BPF_OR | BPF_X):
299 : 0 : BPF_OP_ALU_REG(reg, ins, |, uint64_t);
300 : 0 : break;
301 : 1 : case (EBPF_ALU64 | BPF_LSH | BPF_X):
302 : 1 : BPF_OP_ALU_REG(reg, ins, <<, uint64_t);
303 : 1 : break;
304 : 0 : case (EBPF_ALU64 | BPF_RSH | BPF_X):
305 : 0 : BPF_OP_ALU_REG(reg, ins, >>, uint64_t);
306 : 0 : break;
307 : 1 : case (EBPF_ALU64 | EBPF_ARSH | BPF_X):
308 : 1 : BPF_OP_ALU_REG(reg, ins, >>, int64_t);
309 : 1 : break;
310 : 9 : case (EBPF_ALU64 | BPF_XOR | BPF_X):
311 : 9 : BPF_OP_ALU_REG(reg, ins, ^, uint64_t);
312 : 9 : break;
313 : 1 : case (EBPF_ALU64 | BPF_MUL | BPF_X):
314 : 1 : BPF_OP_ALU_REG(reg, ins, *, uint64_t);
315 : 1 : break;
316 : 1 : case (EBPF_ALU64 | BPF_DIV | BPF_X):
317 [ - + ]: 1 : BPF_DIV_ZERO_CHECK(bpf, reg, ins, uint64_t);
318 : 1 : BPF_OP_ALU_REG(reg, ins, /, uint64_t);
319 : 1 : break;
320 : 0 : case (EBPF_ALU64 | BPF_MOD | BPF_X):
321 [ # # ]: 0 : BPF_DIV_ZERO_CHECK(bpf, reg, ins, uint64_t);
322 : 0 : BPF_OP_ALU_REG(reg, ins, %, uint64_t);
323 : 0 : break;
324 : 29 : case (EBPF_ALU64 | EBPF_MOV | BPF_X):
325 : 29 : EBPF_MOV_ALU_REG(reg, ins, uint64_t);
326 : 29 : break;
327 : 3 : case (EBPF_ALU64 | BPF_NEG):
328 : 3 : BPF_NEG_ALU(reg, ins, uint64_t);
329 : 3 : break;
330 : : /* load instructions */
331 : 8 : case (BPF_LDX | BPF_MEM | BPF_B):
332 : 8 : BPF_LD_REG(reg, ins, uint8_t);
333 : 8 : break;
334 : 7 : case (BPF_LDX | BPF_MEM | BPF_H):
335 : 7 : BPF_LD_REG(reg, ins, uint16_t);
336 : 7 : break;
337 : 22 : case (BPF_LDX | BPF_MEM | BPF_W):
338 : 22 : BPF_LD_REG(reg, ins, uint32_t);
339 : 22 : break;
340 : 16 : case (BPF_LDX | BPF_MEM | EBPF_DW):
341 : 16 : BPF_LD_REG(reg, ins, uint64_t);
342 : 16 : break;
343 : : /* load 64 bit immediate value */
344 : 12 : case (BPF_LD | BPF_IMM | EBPF_DW):
345 : 12 : reg[ins->dst_reg] = (uint32_t)ins[0].imm |
346 : 12 : (uint64_t)(uint32_t)ins[1].imm << 32;
347 : 12 : ins++;
348 : 12 : break;
349 : : /* load absolute instructions */
350 : 3 : case (BPF_LD | BPF_ABS | BPF_B):
351 [ + - ]: 3 : BPF_LD_ABS(bpf, reg, ins, uint8_t, NOP);
352 : 3 : break;
353 : 7 : case (BPF_LD | BPF_ABS | BPF_H):
354 [ + - - + ]: 14 : BPF_LD_ABS(bpf, reg, ins, uint16_t, rte_be_to_cpu_16);
355 : 7 : break;
356 : 3 : case (BPF_LD | BPF_ABS | BPF_W):
357 [ + - - + ]: 6 : BPF_LD_ABS(bpf, reg, ins, uint32_t, rte_be_to_cpu_32);
358 : 3 : break;
359 : : /* load indirect instructions */
360 : 3 : case (BPF_LD | BPF_IND | BPF_B):
361 [ + - ]: 3 : BPF_LD_IND(bpf, reg, ins, uint8_t, NOP);
362 : 3 : break;
363 : 2 : case (BPF_LD | BPF_IND | BPF_H):
364 [ + - - + ]: 4 : BPF_LD_IND(bpf, reg, ins, uint16_t, rte_be_to_cpu_16);
365 : 2 : break;
366 : 3 : case (BPF_LD | BPF_IND | BPF_W):
367 [ + + - + ]: 5 : BPF_LD_IND(bpf, reg, ins, uint32_t, rte_be_to_cpu_32);
368 : 2 : break;
369 : : /* store instructions */
370 : 3 : case (BPF_STX | BPF_MEM | BPF_B):
371 : 3 : BPF_ST_REG(reg, ins, uint8_t);
372 : 3 : break;
373 : 1 : case (BPF_STX | BPF_MEM | BPF_H):
374 : 1 : BPF_ST_REG(reg, ins, uint16_t);
375 : 1 : break;
376 : 6 : case (BPF_STX | BPF_MEM | BPF_W):
377 : 6 : BPF_ST_REG(reg, ins, uint32_t);
378 : 6 : break;
379 : 29 : case (BPF_STX | BPF_MEM | EBPF_DW):
380 : 29 : BPF_ST_REG(reg, ins, uint64_t);
381 : 29 : break;
382 : 5 : case (BPF_ST | BPF_MEM | BPF_B):
383 : 5 : BPF_ST_IMM(reg, ins, uint8_t);
384 : 5 : break;
385 : 1 : case (BPF_ST | BPF_MEM | BPF_H):
386 : 1 : BPF_ST_IMM(reg, ins, uint16_t);
387 : 1 : break;
388 : 1 : case (BPF_ST | BPF_MEM | BPF_W):
389 : 1 : BPF_ST_IMM(reg, ins, uint32_t);
390 : 1 : break;
391 : 1 : case (BPF_ST | BPF_MEM | EBPF_DW):
392 : 1 : BPF_ST_IMM(reg, ins, uint64_t);
393 : 1 : break;
394 : : /* atomic instructions */
395 : 12 : case (BPF_STX | EBPF_ATOMIC | BPF_W):
396 [ + + - ]: 12 : BPF_ST_ATOMIC_REG(reg, ins, 32);
397 : : break;
398 : 12 : case (BPF_STX | EBPF_ATOMIC | EBPF_DW):
399 [ + + - ]: 12 : BPF_ST_ATOMIC_REG(reg, ins, 64);
400 : : break;
401 : : /* jump instructions */
402 : 6 : case (BPF_JMP | BPF_JA):
403 : 6 : BPF_JMP_UNC(ins);
404 : 6 : break;
405 : : /* jump IMM instructions */
406 : 4 : case (BPF_JMP | BPF_JEQ | BPF_K):
407 [ + + ]: 4 : BPF_JMP_CND_IMM(reg, ins, ==, uint64_t);
408 : 4 : break;
409 : 7 : case (BPF_JMP | EBPF_JNE | BPF_K):
410 [ - + ]: 7 : BPF_JMP_CND_IMM(reg, ins, !=, uint64_t);
411 : 7 : break;
412 : 1 : case (BPF_JMP | BPF_JGT | BPF_K):
413 [ + - ]: 1 : BPF_JMP_CND_IMM(reg, ins, >, uint64_t);
414 : 1 : break;
415 : 0 : case (BPF_JMP | EBPF_JLT | BPF_K):
416 [ # # ]: 0 : BPF_JMP_CND_IMM(reg, ins, <, uint64_t);
417 : 0 : break;
418 : 0 : case (BPF_JMP | BPF_JGE | BPF_K):
419 [ # # ]: 0 : BPF_JMP_CND_IMM(reg, ins, >=, uint64_t);
420 : 0 : break;
421 : 0 : case (BPF_JMP | EBPF_JLE | BPF_K):
422 [ # # ]: 0 : BPF_JMP_CND_IMM(reg, ins, <=, uint64_t);
423 : 0 : break;
424 : 0 : case (BPF_JMP | EBPF_JSGT | BPF_K):
425 [ # # ]: 0 : BPF_JMP_CND_IMM(reg, ins, >, int64_t);
426 : 0 : break;
427 : 0 : case (BPF_JMP | EBPF_JSLT | BPF_K):
428 [ # # ]: 0 : BPF_JMP_CND_IMM(reg, ins, <, int64_t);
429 : 0 : break;
430 : 0 : case (BPF_JMP | EBPF_JSGE | BPF_K):
431 [ # # ]: 0 : BPF_JMP_CND_IMM(reg, ins, >=, int64_t);
432 : 0 : break;
433 : 1 : case (BPF_JMP | EBPF_JSLE | BPF_K):
434 [ - + ]: 1 : BPF_JMP_CND_IMM(reg, ins, <=, int64_t);
435 : 1 : break;
436 : 1 : case (BPF_JMP | BPF_JSET | BPF_K):
437 [ + - ]: 1 : BPF_JMP_CND_IMM(reg, ins, &, uint64_t);
438 : 1 : break;
439 : : /* jump REG instructions */
440 : 2 : case (BPF_JMP | BPF_JEQ | BPF_X):
441 [ + + ]: 2 : BPF_JMP_CND_REG(reg, ins, ==, uint64_t);
442 : 2 : break;
443 : 1 : case (BPF_JMP | EBPF_JNE | BPF_X):
444 [ + - ]: 1 : BPF_JMP_CND_REG(reg, ins, !=, uint64_t);
445 : 1 : break;
446 : 0 : case (BPF_JMP | BPF_JGT | BPF_X):
447 [ # # ]: 0 : BPF_JMP_CND_REG(reg, ins, >, uint64_t);
448 : 0 : break;
449 : 0 : case (BPF_JMP | EBPF_JLT | BPF_X):
450 [ # # ]: 0 : BPF_JMP_CND_REG(reg, ins, <, uint64_t);
451 : 0 : break;
452 : 0 : case (BPF_JMP | BPF_JGE | BPF_X):
453 [ # # ]: 0 : BPF_JMP_CND_REG(reg, ins, >=, uint64_t);
454 : 0 : break;
455 : 1 : case (BPF_JMP | EBPF_JLE | BPF_X):
456 [ + - ]: 1 : BPF_JMP_CND_REG(reg, ins, <=, uint64_t);
457 : 1 : break;
458 : 1 : case (BPF_JMP | EBPF_JSGT | BPF_X):
459 [ + - ]: 1 : BPF_JMP_CND_REG(reg, ins, >, int64_t);
460 : 1 : break;
461 : 0 : case (BPF_JMP | EBPF_JSLT | BPF_X):
462 [ # # ]: 0 : BPF_JMP_CND_REG(reg, ins, <, int64_t);
463 : 0 : break;
464 : 0 : case (BPF_JMP | EBPF_JSGE | BPF_X):
465 [ # # ]: 0 : BPF_JMP_CND_REG(reg, ins, >=, int64_t);
466 : 0 : break;
467 : 0 : case (BPF_JMP | EBPF_JSLE | BPF_X):
468 [ # # ]: 0 : BPF_JMP_CND_REG(reg, ins, <=, int64_t);
469 : 0 : break;
470 : 1 : case (BPF_JMP | BPF_JSET | BPF_X):
471 [ + - ]: 1 : BPF_JMP_CND_REG(reg, ins, &, uint64_t);
472 : 1 : break;
473 : : /* call instructions */
474 : 7 : case (BPF_JMP | EBPF_CALL):
475 : 7 : reg[EBPF_REG_0] = bpf->prm.xsym[ins->imm].func.val(
476 : : reg[EBPF_REG_1], reg[EBPF_REG_2],
477 : : reg[EBPF_REG_3], reg[EBPF_REG_4],
478 : : reg[EBPF_REG_5]);
479 : 7 : break;
480 : : /* return instruction */
481 : 26 : case (BPF_JMP | EBPF_EXIT):
482 : 26 : return reg[EBPF_REG_0];
483 : 0 : default:
484 : 0 : RTE_BPF_LOG_LINE(ERR,
485 : : "%s(%p): invalid opcode %#x at pc: %#zx;",
486 : : __func__, bpf, ins->code,
487 : : (uintptr_t)ins - (uintptr_t)bpf->prm.raw.ins);
488 : 0 : return 0;
489 : : }
490 : : }
491 : :
492 : : /* should never be reached */
493 : : RTE_VERIFY(0);
494 : : return 0;
495 : : }
496 : :
497 : : RTE_EXPORT_SYMBOL(rte_bpf_exec_burst)
498 : : uint32_t
499 : 29 : rte_bpf_exec_burst(const struct rte_bpf *bpf, void *ctx[], uint64_t rc[],
500 : : uint32_t num)
501 : : {
502 : : uint32_t i;
503 : : uint64_t reg[EBPF_REG_NUM];
504 : : uint64_t stack[MAX_BPF_STACK_SIZE / sizeof(uint64_t)];
505 : :
506 [ + + ]: 29 : if (bpf->prm.nb_prog_arg != 1) {
507 : : /* Use rte_bpf_exec_burst_ex with this program. */
508 : 1 : rte_errno = EINVAL;
509 : 1 : return 0;
510 : : }
511 : :
512 [ + + ]: 56 : for (i = 0; i != num; i++) {
513 : :
514 : 28 : reg[EBPF_REG_1] = (uintptr_t)ctx[i];
515 : 28 : reg[EBPF_REG_10] = (uintptr_t)(stack + RTE_DIM(stack));
516 : :
517 : 28 : rc[i] = bpf_exec(bpf, reg);
518 : : }
519 : :
520 : : return i;
521 : : }
522 : :
523 : : static uint32_t
524 : 0 : exec_vm_burst_ex(const struct rte_bpf *bpf, const struct rte_bpf_prog_ctx *ctx,
525 : : uint64_t rc[], uint32_t num)
526 : : {
527 : : uint32_t i;
528 : : uint64_t reg[EBPF_REG_NUM];
529 : : uint64_t stack[MAX_BPF_STACK_SIZE / sizeof(uint64_t)];
530 : :
531 [ # # ]: 0 : for (i = 0; i != num; i++) {
532 : :
533 [ # # # # : 0 : switch (bpf->prm.nb_prog_arg) {
# # ]
534 : 0 : case 5:
535 : 0 : reg[EBPF_REG_5] = ctx[i].arg[4].u64;
536 : : /* FALLTHROUGH */
537 : 0 : case 4:
538 : 0 : reg[EBPF_REG_4] = ctx[i].arg[3].u64;
539 : : /* FALLTHROUGH */
540 : 0 : case 3:
541 : 0 : reg[EBPF_REG_3] = ctx[i].arg[2].u64;
542 : : /* FALLTHROUGH */
543 : 0 : case 2:
544 : 0 : reg[EBPF_REG_2] = ctx[i].arg[1].u64;
545 : : /* FALLTHROUGH */
546 : 0 : case 1:
547 : 0 : reg[EBPF_REG_1] = ctx[i].arg[0].u64;
548 : : /* FALLTHROUGH */
549 : : case 0:
550 : : break;
551 : : }
552 : :
553 : 0 : reg[EBPF_REG_10] = (uintptr_t)(stack + RTE_DIM(stack));
554 : :
555 : 0 : rc[i] = bpf_exec(bpf, reg);
556 : : }
557 : :
558 : 0 : return i;
559 : : }
560 : :
561 : : static uint32_t
562 : 0 : exec_jit_burst_ex(const struct rte_bpf *bpf, const struct rte_bpf_prog_ctx *ctx,
563 : : uint64_t rc[], uint32_t num)
564 : : {
565 : : uint32_t i = 0;
566 : 0 : const struct rte_bpf_jit_ex jit = bpf->jit;
567 : :
568 : : /*
569 : : * Fast path: assumes application pre-validated RTE_BPF_EXEC_FLAG_JIT
570 : : * and successful JIT generation. No explicit NULL checks here.
571 : : */
572 [ # # # # : 0 : switch (bpf->prm.nb_prog_arg) {
# # # ]
573 : : case 0:
574 [ # # ]: 0 : for (i = 0; i != num; i++)
575 : 0 : rc[i] = jit.func0();
576 : : break;
577 : : case 1:
578 [ # # ]: 0 : for (i = 0; i != num; i++) {
579 : 0 : const union rte_bpf_func_arg *const arg = ctx[i].arg;
580 : 0 : rc[i] = jit.func1(arg[0]);
581 : : }
582 : : break;
583 : : case 2:
584 [ # # ]: 0 : for (i = 0; i != num; i++) {
585 : 0 : const union rte_bpf_func_arg *const arg = ctx[i].arg;
586 : 0 : rc[i] = jit.func2(arg[0], arg[1]);
587 : : }
588 : : break;
589 : : case 3:
590 [ # # ]: 0 : for (i = 0; i != num; i++) {
591 : 0 : const union rte_bpf_func_arg *const arg = ctx[i].arg;
592 : 0 : rc[i] = jit.func3(arg[0], arg[1], arg[2]);
593 : : }
594 : : break;
595 : : case 4:
596 [ # # ]: 0 : for (i = 0; i != num; i++) {
597 : 0 : const union rte_bpf_func_arg *const arg = ctx[i].arg;
598 : 0 : rc[i] = jit.func4(arg[0], arg[1], arg[2], arg[3]);
599 : : }
600 : : break;
601 : : case 5:
602 [ # # ]: 0 : for (i = 0; i != num; i++) {
603 : 0 : const union rte_bpf_func_arg *const arg = ctx[i].arg;
604 : 0 : rc[i] = jit.func5(arg[0], arg[1], arg[2], arg[3], arg[4]);
605 : : }
606 : : break;
607 : : }
608 : :
609 : 0 : return i;
610 : : }
611 : :
612 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_bpf_exec_burst_ex, 26.07)
613 : : uint32_t
614 : 1 : rte_bpf_exec_burst_ex(const struct rte_bpf *bpf, const struct rte_bpf_prog_ctx *ctx,
615 : : uint64_t rc[], uint32_t num, uint64_t flags)
616 : : {
617 [ + - ]: 1 : if ((flags & ~RTE_BPF_EXEC_FLAG_MASK) != 0) {
618 : 1 : rte_errno = EINVAL;
619 : 1 : return 0;
620 : : }
621 : :
622 : 0 : return (flags & RTE_BPF_EXEC_FLAG_JIT) != 0 ?
623 [ # # ]: 0 : exec_jit_burst_ex(bpf, ctx, rc, num) :
624 : 0 : exec_vm_burst_ex(bpf, ctx, rc, num);
625 : : }
626 : :
627 : : RTE_EXPORT_SYMBOL(rte_bpf_exec)
628 : : uint64_t
629 : 28 : rte_bpf_exec(const struct rte_bpf *bpf, void *ctx)
630 : : {
631 : 28 : uint64_t rc = UINT64_MAX;
632 : :
633 : 28 : rte_bpf_exec_burst(bpf, &ctx, &rc, 1);
634 : 28 : return rc;
635 : : }
636 : :
637 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_bpf_exec_ex, 26.07)
638 : : uint64_t
639 : 0 : rte_bpf_exec_ex(const struct rte_bpf *bpf, const struct rte_bpf_prog_ctx *ctx,
640 : : uint64_t flags)
641 : : {
642 : 0 : uint64_t rc = UINT64_MAX;
643 : :
644 : 0 : rte_bpf_exec_burst_ex(bpf, ctx, &rc, 1, flags);
645 : 0 : return rc;
646 : : }
|