Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2021 Microsoft Corporation
3 : : *
4 : : * Based on bpf_convert_filter() in the Linux kernel sources
5 : : * and filter2xdp.
6 : : *
7 : : * Licensed as BSD with permission original authors.
8 : : * Copyright (C) 2017 Tobias Klauser
9 : : * Copyright (c) 2011 - 2014 PLUMgrid, http://plumgrid.com
10 : : */
11 : :
12 : : #include <assert.h>
13 : : #include <errno.h>
14 : : #include <stdbool.h>
15 : : #include <stddef.h>
16 : : #include <stdint.h>
17 : : #include <stdlib.h>
18 : : #include <string.h>
19 : :
20 : : #include <eal_export.h>
21 : : #include <rte_common.h>
22 : : #include <rte_bpf.h>
23 : : #include <rte_log.h>
24 : : #include <rte_malloc.h>
25 : : #include <rte_errno.h>
26 : :
27 : : #include <pcap/pcap.h>
28 : : #include <pcap/bpf.h>
29 : :
30 : : #include "bpf_impl.h"
31 : : #include "bpf_def.h"
32 : :
33 : : #ifndef BPF_MAXINSNS
34 : : #define BPF_MAXINSNS 4096
35 : : #endif
36 : :
37 : : /*
38 : : * Linux socket filter uses negative absolute offsets to
39 : : * reference ancillary data.
40 : : */
41 : : #define SKF_AD_OFF (-0x1000)
42 : : #define SKF_AD_PROTOCOL 0
43 : : #define SKF_AD_PKTTYPE 4
44 : : #define SKF_AD_IFINDEX 8
45 : : #define SKF_AD_NLATTR 12
46 : : #define SKF_AD_NLATTR_NEST 16
47 : : #define SKF_AD_MARK 20
48 : : #define SKF_AD_QUEUE 24
49 : : #define SKF_AD_HATYPE 28
50 : : #define SKF_AD_RXHASH 32
51 : : #define SKF_AD_CPU 36
52 : : #define SKF_AD_ALU_XOR_X 40
53 : : #define SKF_AD_VLAN_TAG 44
54 : : #define SKF_AD_VLAN_TAG_PRESENT 48
55 : : #define SKF_AD_PAY_OFFSET 52
56 : : #define SKF_AD_RANDOM 56
57 : : #define SKF_AD_VLAN_TPID 60
58 : : #define SKF_AD_MAX 64
59 : :
60 : : /* ArgX, context and stack frame pointer register positions. Note,
61 : : * Arg1, Arg2, Arg3, etc are used as argument mappings of function
62 : : * calls in BPF_CALL instruction.
63 : : */
64 : : #define BPF_REG_ARG1 EBPF_REG_1
65 : : #define BPF_REG_ARG2 EBPF_REG_2
66 : : #define BPF_REG_ARG3 EBPF_REG_3
67 : : #define BPF_REG_ARG4 EBPF_REG_4
68 : : #define BPF_REG_ARG5 EBPF_REG_5
69 : : #define BPF_REG_CTX EBPF_REG_6
70 : : #define BPF_REG_FP EBPF_REG_10
71 : :
72 : : /* Additional register mappings for converted user programs. */
73 : : #define BPF_REG_A EBPF_REG_0
74 : : #define BPF_REG_X EBPF_REG_7
75 : : #define BPF_REG_TMP EBPF_REG_8
76 : :
77 : : /* Helper macros for filter block array initializers. */
78 : :
79 : : /* ALU ops on registers, bpf_add|sub|...: dst_reg += src_reg */
80 : :
81 : : #define EBPF_ALU64_REG(OP, DST, SRC) \
82 : : ((struct ebpf_insn) { \
83 : : .code = EBPF_ALU64 | BPF_OP(OP) | BPF_X, \
84 : : .dst_reg = DST, \
85 : : .src_reg = SRC, \
86 : : .off = 0, \
87 : : .imm = 0 })
88 : :
89 : : #define BPF_ALU32_REG(OP, DST, SRC) \
90 : : ((struct ebpf_insn) { \
91 : : .code = BPF_ALU | BPF_OP(OP) | BPF_X, \
92 : : .dst_reg = DST, \
93 : : .src_reg = SRC, \
94 : : .off = 0, \
95 : : .imm = 0 })
96 : :
97 : : /* ALU ops on immediates, bpf_add|sub|...: dst_reg += imm32 */
98 : :
99 : : #define BPF_ALU32_IMM(OP, DST, IMM) \
100 : : ((struct ebpf_insn) { \
101 : : .code = BPF_ALU | BPF_OP(OP) | BPF_K, \
102 : : .dst_reg = DST, \
103 : : .src_reg = 0, \
104 : : .off = 0, \
105 : : .imm = IMM })
106 : :
107 : : /* Short form of mov, dst_reg = src_reg */
108 : :
109 : : #define BPF_MOV64_REG(DST, SRC) \
110 : : ((struct ebpf_insn) { \
111 : : .code = EBPF_ALU64 | EBPF_MOV | BPF_X, \
112 : : .dst_reg = DST, \
113 : : .src_reg = SRC, \
114 : : .off = 0, \
115 : : .imm = 0 })
116 : :
117 : : #define BPF_MOV32_REG(DST, SRC) \
118 : : ((struct ebpf_insn) { \
119 : : .code = BPF_ALU | EBPF_MOV | BPF_X, \
120 : : .dst_reg = DST, \
121 : : .src_reg = SRC, \
122 : : .off = 0, \
123 : : .imm = 0 })
124 : :
125 : : /* Short form of mov, dst_reg = imm32 */
126 : :
127 : : #define BPF_MOV32_IMM(DST, IMM) \
128 : : ((struct ebpf_insn) { \
129 : : .code = BPF_ALU | EBPF_MOV | BPF_K, \
130 : : .dst_reg = DST, \
131 : : .src_reg = 0, \
132 : : .off = 0, \
133 : : .imm = IMM })
134 : :
135 : : /* Short form of mov based on type, BPF_X: dst_reg = src_reg, BPF_K: dst_reg = imm32 */
136 : :
137 : : #define BPF_MOV32_RAW(TYPE, DST, SRC, IMM) \
138 : : ((struct ebpf_insn) { \
139 : : .code = BPF_ALU | EBPF_MOV | BPF_SRC(TYPE), \
140 : : .dst_reg = DST, \
141 : : .src_reg = SRC, \
142 : : .off = 0, \
143 : : .imm = IMM })
144 : :
145 : : /* Direct packet access, R0 = *(uint *) (skb->data + imm32) */
146 : :
147 : : #define BPF_LD_ABS(SIZE, IMM) \
148 : : ((struct ebpf_insn) { \
149 : : .code = BPF_LD | BPF_SIZE(SIZE) | BPF_ABS, \
150 : : .dst_reg = 0, \
151 : : .src_reg = 0, \
152 : : .off = 0, \
153 : : .imm = IMM })
154 : :
155 : : /* Memory load, dst_reg = *(uint *) (src_reg + off16) */
156 : :
157 : : #define BPF_LDX_MEM(SIZE, DST, SRC, OFF) \
158 : : ((struct ebpf_insn) { \
159 : : .code = BPF_LDX | BPF_SIZE(SIZE) | BPF_MEM, \
160 : : .dst_reg = DST, \
161 : : .src_reg = SRC, \
162 : : .off = OFF, \
163 : : .imm = 0 })
164 : :
165 : : /* Memory store, *(uint *) (dst_reg + off16) = src_reg */
166 : :
167 : : #define BPF_STX_MEM(SIZE, DST, SRC, OFF) \
168 : : ((struct ebpf_insn) { \
169 : : .code = BPF_STX | BPF_SIZE(SIZE) | BPF_MEM, \
170 : : .dst_reg = DST, \
171 : : .src_reg = SRC, \
172 : : .off = OFF, \
173 : : .imm = 0 })
174 : :
175 : : /* Conditional jumps against immediates, if (dst_reg 'op' imm32) goto pc + off16 */
176 : :
177 : : #define BPF_JMP_IMM(OP, DST, IMM, OFF) \
178 : : ((struct ebpf_insn) { \
179 : : .code = BPF_JMP | BPF_OP(OP) | BPF_K, \
180 : : .dst_reg = DST, \
181 : : .src_reg = 0, \
182 : : .off = OFF, \
183 : : .imm = IMM })
184 : :
185 : : /* Raw code statement block */
186 : :
187 : : #define BPF_RAW_INSN(CODE, DST, SRC, OFF, IMM) \
188 : : ((struct ebpf_insn) { \
189 : : .code = CODE, \
190 : : .dst_reg = DST, \
191 : : .src_reg = SRC, \
192 : : .off = OFF, \
193 : : .imm = IMM })
194 : :
195 : : /* Program exit */
196 : :
197 : : #define BPF_EXIT_INSN() \
198 : : ((struct ebpf_insn) { \
199 : : .code = BPF_JMP | EBPF_EXIT, \
200 : : .dst_reg = 0, \
201 : : .src_reg = 0, \
202 : : .off = 0, \
203 : : .imm = 0 })
204 : :
205 : : /*
206 : : * Placeholder to convert BPF extensions like length and VLAN tag
207 : : * If and when DPDK BPF supports them.
208 : : */
209 : 582 : static bool convert_bpf_load(const struct bpf_insn *fp,
210 : : struct ebpf_insn **new_insnp __rte_unused)
211 : : {
212 [ - + ]: 582 : switch (fp->k) {
213 : 0 : case SKF_AD_OFF + SKF_AD_PROTOCOL:
214 : : case SKF_AD_OFF + SKF_AD_PKTTYPE:
215 : : case SKF_AD_OFF + SKF_AD_IFINDEX:
216 : : case SKF_AD_OFF + SKF_AD_HATYPE:
217 : : case SKF_AD_OFF + SKF_AD_MARK:
218 : : case SKF_AD_OFF + SKF_AD_RXHASH:
219 : : case SKF_AD_OFF + SKF_AD_QUEUE:
220 : : case SKF_AD_OFF + SKF_AD_VLAN_TAG:
221 : : case SKF_AD_OFF + SKF_AD_VLAN_TAG_PRESENT:
222 : : case SKF_AD_OFF + SKF_AD_VLAN_TPID:
223 : : case SKF_AD_OFF + SKF_AD_PAY_OFFSET:
224 : : case SKF_AD_OFF + SKF_AD_NLATTR:
225 : : case SKF_AD_OFF + SKF_AD_NLATTR_NEST:
226 : : case SKF_AD_OFF + SKF_AD_CPU:
227 : : case SKF_AD_OFF + SKF_AD_RANDOM:
228 : : case SKF_AD_OFF + SKF_AD_ALU_XOR_X:
229 : : /* Linux has special negative offsets to access meta-data. */
230 : 0 : RTE_BPF_LOG_LINE(ERR,
231 : : "rte_bpf_convert: socket offset %d not supported",
232 : : fp->k - SKF_AD_OFF);
233 : 0 : return true;
234 : : default:
235 : : return false;
236 : : }
237 : : }
238 : :
239 : 56 : static int bpf_convert_filter(const struct bpf_insn *prog, size_t len,
240 : : struct ebpf_insn *new_prog, uint32_t *new_len)
241 : : {
242 : : unsigned int pass = 0;
243 : : size_t new_flen = 0, target, i;
244 : : struct ebpf_insn *new_insn;
245 : : const struct bpf_insn *fp;
246 : : int *addrs = NULL;
247 : : uint8_t bpf_src;
248 : :
249 [ - + ]: 56 : if (len > BPF_MAXINSNS) {
250 : 0 : RTE_BPF_LOG_LINE(ERR, "%s: cBPF program too long (%zu insns)",
251 : : __func__, len);
252 : 0 : return -EINVAL;
253 : : }
254 : :
255 : : /* On second pass, allocate the new program */
256 [ + + ]: 56 : if (new_prog) {
257 : 28 : addrs = calloc(len, sizeof(*addrs));
258 [ + - ]: 28 : if (addrs == NULL)
259 : : return -ENOMEM;
260 : : }
261 : :
262 : 56 : do_pass:
263 : : new_insn = new_prog;
264 : : fp = prog;
265 : :
266 : : /* Classic BPF related prologue emission. */
267 [ + + ]: 84 : if (new_insn) {
268 : : /* Classic BPF expects A and X to be reset first. These need
269 : : * to be guaranteed to be the first two instructions.
270 : : */
271 : 56 : *new_insn++ = EBPF_ALU64_REG(BPF_XOR, BPF_REG_A, BPF_REG_A);
272 : 56 : *new_insn++ = EBPF_ALU64_REG(BPF_XOR, BPF_REG_X, BPF_REG_X);
273 : :
274 : : /* All programs must keep CTX in callee saved BPF_REG_CTX.
275 : : * In eBPF case it's done by the compiler, here we need to
276 : : * do this ourself. Initial CTX is present in BPF_REG_ARG1.
277 : : */
278 : 56 : *new_insn++ = BPF_MOV64_REG(BPF_REG_CTX, BPF_REG_ARG1);
279 : : } else {
280 : : new_insn += 3;
281 : : }
282 : :
283 [ + + ]: 1926 : for (i = 0; i < len; fp++, i++) {
284 : 1842 : struct ebpf_insn tmp_insns[6] = { };
285 : 1842 : struct ebpf_insn *insn = tmp_insns;
286 : :
287 [ + + ]: 1842 : if (addrs)
288 : 1228 : addrs[i] = new_insn - new_prog;
289 : :
290 [ + - + - : 1842 : switch (fp->code) {
+ + + + +
+ + - +
- ]
291 : : /* Absolute loads are how classic BPF accesses skb */
292 : 582 : case BPF_LD | BPF_ABS | BPF_W:
293 : : case BPF_LD | BPF_ABS | BPF_H:
294 : : case BPF_LD | BPF_ABS | BPF_B:
295 [ - + ]: 582 : if (convert_bpf_load(fp, &insn))
296 : 0 : goto err;
297 : :
298 : 582 : *insn = BPF_RAW_INSN(fp->code, 0, 0, 0, fp->k);
299 : 582 : break;
300 : :
301 : 0 : case BPF_ALU | BPF_DIV | BPF_X:
302 : : case BPF_ALU | BPF_MOD | BPF_X:
303 : : /* For cBPF, don't cause floating point exception */
304 : 0 : *insn++ = BPF_MOV32_REG(BPF_REG_X, BPF_REG_X);
305 : 0 : *insn++ = BPF_JMP_IMM(EBPF_JNE, BPF_REG_X, 0, 2);
306 : 0 : *insn++ = BPF_ALU32_REG(BPF_XOR, BPF_REG_A, BPF_REG_A);
307 : 0 : *insn++ = BPF_EXIT_INSN();
308 : : /* fallthrough */
309 : 192 : case BPF_ALU | BPF_ADD | BPF_X:
310 : : case BPF_ALU | BPF_ADD | BPF_K:
311 : : case BPF_ALU | BPF_SUB | BPF_X:
312 : : case BPF_ALU | BPF_SUB | BPF_K:
313 : : case BPF_ALU | BPF_AND | BPF_X:
314 : : case BPF_ALU | BPF_AND | BPF_K:
315 : : case BPF_ALU | BPF_OR | BPF_X:
316 : : case BPF_ALU | BPF_OR | BPF_K:
317 : : case BPF_ALU | BPF_LSH | BPF_X:
318 : : case BPF_ALU | BPF_LSH | BPF_K:
319 : : case BPF_ALU | BPF_RSH | BPF_X:
320 : : case BPF_ALU | BPF_RSH | BPF_K:
321 : : case BPF_ALU | BPF_XOR | BPF_X:
322 : : case BPF_ALU | BPF_XOR | BPF_K:
323 : : case BPF_ALU | BPF_MUL | BPF_X:
324 : : case BPF_ALU | BPF_MUL | BPF_K:
325 : : case BPF_ALU | BPF_DIV | BPF_K:
326 : : case BPF_ALU | BPF_MOD | BPF_K:
327 : : case BPF_ALU | BPF_NEG:
328 : : case BPF_LD | BPF_IND | BPF_W:
329 : : case BPF_LD | BPF_IND | BPF_H:
330 : : case BPF_LD | BPF_IND | BPF_B:
331 : : /* All arithmetic insns map as-is. */
332 : 192 : insn->code = fp->code;
333 : 192 : insn->dst_reg = BPF_REG_A;
334 : 192 : bpf_src = BPF_SRC(fp->code);
335 [ + + ]: 192 : insn->src_reg = bpf_src == BPF_X ? BPF_REG_X : 0;
336 : 192 : insn->off = 0;
337 : 192 : insn->imm = fp->k;
338 : 192 : break;
339 : :
340 : : /* Jump transformation cannot use BPF block macros
341 : : * everywhere as offset calculation and target updates
342 : : * require a bit more work than the rest, i.e. jump
343 : : * opcodes map as-is, but offsets need adjustment.
344 : : */
345 : :
346 : : #define BPF_EMIT_JMP \
347 : : do { \
348 : : if (target >= len) \
349 : : goto err; \
350 : : insn->off = addrs ? addrs[target] - addrs[i] - 1 : 0; \
351 : : /* Adjust pc relative offset for 2nd or 3rd insn. */ \
352 : : insn->off -= insn - tmp_insns; \
353 : : } while (0)
354 : :
355 : 0 : case BPF_JMP | BPF_JA:
356 : 0 : target = i + fp->k + 1;
357 : 0 : insn->code = fp->code;
358 [ # # # # ]: 0 : BPF_EMIT_JMP;
359 : 0 : break;
360 : :
361 : 813 : case BPF_JMP | BPF_JEQ | BPF_K:
362 : : case BPF_JMP | BPF_JEQ | BPF_X:
363 : : case BPF_JMP | BPF_JSET | BPF_K:
364 : : case BPF_JMP | BPF_JSET | BPF_X:
365 : : case BPF_JMP | BPF_JGT | BPF_K:
366 : : case BPF_JMP | BPF_JGT | BPF_X:
367 : : case BPF_JMP | BPF_JGE | BPF_K:
368 : : case BPF_JMP | BPF_JGE | BPF_X:
369 [ + - + + ]: 813 : if (BPF_SRC(fp->code) == BPF_K && (int) fp->k < 0) {
370 : : /* BPF immediates are signed, zero extend
371 : : * immediate into tmp register and use it
372 : : * in compare insn.
373 : : */
374 : 105 : *insn++ = BPF_MOV32_IMM(BPF_REG_TMP, fp->k);
375 : :
376 : : insn->dst_reg = BPF_REG_A;
377 : 105 : insn->src_reg = BPF_REG_TMP;
378 : : bpf_src = BPF_X;
379 : : } else {
380 : : insn->dst_reg = BPF_REG_A;
381 : 708 : insn->imm = fp->k;
382 : 708 : bpf_src = BPF_SRC(fp->code);
383 [ + - ]: 1416 : insn->src_reg = bpf_src == BPF_X ? BPF_REG_X : 0;
384 : : }
385 : :
386 : : /* Common case where 'jump_false' is next insn. */
387 [ + + ]: 813 : if (fp->jf == 0) {
388 : 285 : insn->code = BPF_JMP | BPF_OP(fp->code) | bpf_src;
389 : 285 : target = i + fp->jt + 1;
390 [ - + + + ]: 285 : BPF_EMIT_JMP;
391 : 285 : break;
392 : : }
393 : :
394 : : /* Convert JEQ into JNE when 'jump_true' is next insn. */
395 [ + + + + ]: 528 : if (fp->jt == 0 && BPF_OP(fp->code) == BPF_JEQ) {
396 : 468 : insn->code = BPF_JMP | EBPF_JNE | bpf_src;
397 : 468 : target = i + fp->jf + 1;
398 [ - + + + ]: 468 : BPF_EMIT_JMP;
399 : 468 : break;
400 : : }
401 : :
402 : : /* Other jumps are mapped into two insns: Jxx and JA. */
403 : 60 : target = i + fp->jt + 1;
404 : 60 : insn->code = BPF_JMP | BPF_OP(fp->code) | bpf_src;
405 [ - + + + ]: 60 : BPF_EMIT_JMP;
406 : 60 : insn++;
407 : :
408 : 60 : insn->code = BPF_JMP | BPF_JA;
409 : 60 : target = i + fp->jf + 1;
410 [ - + + + ]: 60 : BPF_EMIT_JMP;
411 : 60 : break;
412 : :
413 : : /* ldxb 4 * ([14] & 0xf) is remapped into 6 insns. */
414 : 42 : case BPF_LDX | BPF_MSH | BPF_B:
415 : : /* tmp = A */
416 : 42 : *insn++ = BPF_MOV64_REG(BPF_REG_TMP, BPF_REG_A);
417 : : /* A = BPF_R0 = *(u8 *) (skb->data + K) */
418 : 42 : *insn++ = BPF_LD_ABS(BPF_B, fp->k);
419 : : /* A &= 0xf */
420 : 42 : *insn++ = BPF_ALU32_IMM(BPF_AND, BPF_REG_A, 0xf);
421 : : /* A <<= 2 */
422 : 42 : *insn++ = BPF_ALU32_IMM(BPF_LSH, BPF_REG_A, 2);
423 : : /* X = A */
424 : 42 : *insn++ = BPF_MOV64_REG(BPF_REG_X, BPF_REG_A);
425 : : /* A = tmp */
426 : 42 : *insn = BPF_MOV64_REG(BPF_REG_A, BPF_REG_TMP);
427 : 42 : break;
428 : :
429 : : /* RET_K is remapped into 2 insns. RET_A case doesn't need an
430 : : * extra mov as EBPF_REG_0 is already mapped into BPF_REG_A.
431 : : */
432 : 168 : case BPF_RET | BPF_A:
433 : : case BPF_RET | BPF_K:
434 [ + - ]: 168 : if (BPF_RVAL(fp->code) == BPF_K) {
435 : 168 : *insn++ = BPF_MOV32_RAW(BPF_K, EBPF_REG_0,
436 : : 0, fp->k);
437 : : }
438 : 168 : *insn = BPF_EXIT_INSN();
439 : 168 : break;
440 : :
441 : : /* Store to stack. */
442 : 6 : case BPF_ST:
443 : : case BPF_STX:
444 [ - + ]: 6 : *insn = BPF_STX_MEM(BPF_W, BPF_REG_FP, BPF_CLASS(fp->code) ==
445 : : BPF_ST ? BPF_REG_A : BPF_REG_X,
446 : : -(BPF_MEMWORDS - fp->k) * 4);
447 : 6 : break;
448 : :
449 : : /* Load from stack. */
450 : 6 : case BPF_LD | BPF_MEM:
451 : : case BPF_LDX | BPF_MEM:
452 [ - + ]: 6 : *insn = BPF_LDX_MEM(BPF_W, BPF_CLASS(fp->code) == BPF_LD ?
453 : : BPF_REG_A : BPF_REG_X, BPF_REG_FP,
454 : : -(BPF_MEMWORDS - fp->k) * 4);
455 : 6 : break;
456 : :
457 : : /* A = K or X = K */
458 : 6 : case BPF_LD | BPF_IMM:
459 : : case BPF_LDX | BPF_IMM:
460 [ - + ]: 6 : *insn = BPF_MOV32_IMM(BPF_CLASS(fp->code) == BPF_LD ?
461 : : BPF_REG_A : BPF_REG_X, fp->k);
462 : 6 : break;
463 : :
464 : : /* X = A */
465 : 24 : case BPF_MISC | BPF_TAX:
466 : 24 : *insn = BPF_MOV64_REG(BPF_REG_X, BPF_REG_A);
467 : 24 : break;
468 : :
469 : : /* A = X */
470 : 0 : case BPF_MISC | BPF_TXA:
471 : 0 : *insn = BPF_MOV64_REG(BPF_REG_A, BPF_REG_X);
472 : 0 : break;
473 : :
474 : : /* A = mbuf->len or X = mbuf->len */
475 : 3 : case BPF_LD | BPF_W | BPF_LEN:
476 : : case BPF_LDX | BPF_W | BPF_LEN:
477 : : /* BPF_ABS/BPF_IND implicitly expect mbuf ptr in R6 */
478 : :
479 [ - + ]: 3 : *insn = BPF_LDX_MEM(BPF_W, BPF_CLASS(fp->code) == BPF_LD ?
480 : : BPF_REG_A : BPF_REG_X, BPF_REG_CTX,
481 : : offsetof(struct rte_mbuf, pkt_len));
482 : 3 : break;
483 : :
484 : : /* Unknown instruction. */
485 : 0 : default:
486 : 0 : RTE_BPF_LOG_LINE(ERR, "%s: Unknown instruction!: %#x",
487 : : __func__, fp->code);
488 : 0 : goto err;
489 : : }
490 : :
491 : 1842 : insn++;
492 [ + + ]: 1842 : if (new_prog)
493 : 1228 : memcpy(new_insn, tmp_insns,
494 : 1228 : sizeof(*insn) * (insn - tmp_insns));
495 : 1842 : new_insn += insn - tmp_insns;
496 : : }
497 : :
498 [ + + ]: 84 : if (!new_prog) {
499 : : /* Only calculating new length. */
500 : 28 : *new_len = new_insn - new_prog;
501 : 28 : return 0;
502 : : }
503 : :
504 : 56 : pass++;
505 [ + + ]: 56 : if ((ptrdiff_t)new_flen != new_insn - new_prog) {
506 : 28 : new_flen = new_insn - new_prog;
507 [ - + ]: 28 : if (pass > 2)
508 : 0 : goto err;
509 : 28 : goto do_pass;
510 : : }
511 : :
512 : 28 : free(addrs);
513 [ - + ]: 28 : assert(*new_len == new_flen);
514 : :
515 : : return 0;
516 : 0 : err:
517 : 0 : free(addrs);
518 : 0 : return -1;
519 : : }
520 : :
521 : : RTE_EXPORT_SYMBOL(rte_bpf_convert)
522 : : struct rte_bpf_prm *
523 : 28 : rte_bpf_convert(const struct bpf_program *prog)
524 : : {
525 : : struct rte_bpf_prm *prm = NULL;
526 : : struct ebpf_insn *ebpf = NULL;
527 : 28 : uint32_t ebpf_len = 0;
528 : : int ret;
529 : :
530 [ - + ]: 28 : if (prog == NULL) {
531 : 0 : RTE_BPF_LOG_LINE(ERR, "%s: NULL program", __func__);
532 : 0 : rte_errno = EINVAL;
533 : 0 : return NULL;
534 : : }
535 : :
536 : : /* 1st pass: calculate the eBPF program length */
537 : 28 : ret = bpf_convert_filter(prog->bf_insns, prog->bf_len, NULL, &ebpf_len);
538 [ - + ]: 28 : if (ret < 0) {
539 : 0 : RTE_BPF_LOG_LINE(ERR, "%s: cannot get eBPF length", __func__);
540 : 0 : rte_errno = -ret;
541 : 0 : return NULL;
542 : : }
543 : :
544 : 28 : RTE_BPF_LOG_LINE(DEBUG, "%s: prog len cBPF=%u -> eBPF=%u",
545 : : __func__, prog->bf_len, ebpf_len);
546 : :
547 : 28 : prm = rte_zmalloc("bpf_filter",
548 : 28 : sizeof(*prm) + ebpf_len * sizeof(*ebpf), 0);
549 [ - + ]: 28 : if (prm == NULL) {
550 : 0 : rte_errno = ENOMEM;
551 : 0 : return NULL;
552 : : }
553 : :
554 : : /* The EPBF instructions in this case are right after the header */
555 : 28 : ebpf = (void *)(prm + 1);
556 : :
557 : : /* 2nd pass: remap cBPF to eBPF instructions */
558 : 28 : ret = bpf_convert_filter(prog->bf_insns, prog->bf_len, ebpf, &ebpf_len);
559 [ - + ]: 28 : if (ret < 0) {
560 : 0 : RTE_BPF_LOG_LINE(ERR, "%s: cannot convert cBPF to eBPF", __func__);
561 : 0 : rte_free(prm);
562 : 0 : rte_errno = -ret;
563 : 0 : return NULL;
564 : : }
565 : :
566 : 28 : prm->ins = ebpf;
567 : 28 : prm->nb_ins = ebpf_len;
568 : :
569 : : /* Classic BPF programs use mbufs */
570 : 28 : prm->prog_arg.type = RTE_BPF_ARG_PTR_MBUF;
571 : 28 : prm->prog_arg.size = sizeof(struct rte_mbuf);
572 : :
573 : 28 : return prm;
574 : : }
|