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