diff options
author | jkim <jkim@FreeBSD.org> | 2005-12-06 02:58:12 +0000 |
---|---|---|
committer | jkim <jkim@FreeBSD.org> | 2005-12-06 02:58:12 +0000 |
commit | 055dc8e12114d91b9d472f6f1f094db4fc8470dc (patch) | |
tree | 71349d8c0b4cb1d3877c774dc90e493e18151057 | |
parent | ce48506ba2c49b3a1814ff2cfa69af48afde0097 (diff) | |
download | FreeBSD-src-055dc8e12114d91b9d472f6f1f094db4fc8470dc.zip FreeBSD-src-055dc8e12114d91b9d472f6f1f094db4fc8470dc.tar.gz |
Add experimental BPF Just-In-Time compiler for amd64 and i386.
Use the following kernel configuration option to enable:
options BPF_JITTER
If you want to use bpf_filter() instead (e. g., debugging), do:
sysctl net.bpf.jitter.enable=0
to turn it off.
Currently BIOCSETWF and bpf_mtap2() are unsupported, and bpf_mtap() is
partially supported because 1) no need, 2) avoid expensive m_copydata(9).
Obtained from: WinPcap 3.1 (for i386)
-rw-r--r-- | sys/amd64/amd64/bpf_jit_machdep.c | 490 | ||||
-rw-r--r-- | sys/amd64/amd64/bpf_jit_machdep.h | 431 | ||||
-rw-r--r-- | sys/conf/files | 1 | ||||
-rw-r--r-- | sys/conf/files.amd64 | 1 | ||||
-rw-r--r-- | sys/conf/files.i386 | 1 | ||||
-rw-r--r-- | sys/conf/options.amd64 | 3 | ||||
-rw-r--r-- | sys/conf/options.i386 | 3 | ||||
-rw-r--r-- | sys/i386/i386/bpf_jit_machdep.c | 510 | ||||
-rw-r--r-- | sys/i386/i386/bpf_jit_machdep.h | 398 | ||||
-rw-r--r-- | sys/net/bpf.c | 57 | ||||
-rw-r--r-- | sys/net/bpf_jitter.c | 85 | ||||
-rw-r--r-- | sys/net/bpf_jitter.h | 80 | ||||
-rw-r--r-- | sys/net/bpfdesc.h | 3 |
13 files changed, 2060 insertions, 3 deletions
diff --git a/sys/amd64/amd64/bpf_jit_machdep.c b/sys/amd64/amd64/bpf_jit_machdep.c new file mode 100644 index 0000000..2f9dd21 --- /dev/null +++ b/sys/amd64/amd64/bpf_jit_machdep.c @@ -0,0 +1,490 @@ +/*- + * Copyright (c) 2002 - 2003 NetGroup, Politecnico di Torino (Italy) + * Copyright (c) 2005 Jung-uk Kim <jkim@FreeBSD.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Politecnico di Torino nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS intERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "opt_bpf.h" + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/malloc.h> + +#include <net/if.h> +#include <net/bpf.h> +#include <net/bpf_jitter.h> + +#include <amd64/amd64/bpf_jit_machdep.h> + +bpf_filter_func bpf_jit_compile(struct bpf_insn *, u_int, int *); + +/* + * emit routine to update the jump table + */ +static void +emit_length(bpf_bin_stream *stream, u_int value, u_int len) +{ + + (stream->refs)[stream->bpf_pc] += len; + stream->cur_ip += len; +} + +/* + * emit routine to output the actual binary code + */ +static void +emit_code(bpf_bin_stream *stream, u_int value, u_int len) +{ + + switch (len) { + case 1: + stream->ibuf[stream->cur_ip] = (u_char)value; + stream->cur_ip++; + break; + + case 2: + *((u_short *)(stream->ibuf + stream->cur_ip)) = (u_short)value; + stream->cur_ip += 2; + break; + + case 4: + *((u_int *)(stream->ibuf + stream->cur_ip)) = value; + stream->cur_ip += 4; + break; + } + + return; +} + +/* + * Function that does the real stuff + */ +bpf_filter_func +bpf_jit_compile(struct bpf_insn *prog, u_int nins, int *mem) +{ + struct bpf_insn *ins; + u_int i, pass; + bpf_bin_stream stream; + + /* + * NOTE: do not modify the name of this variable, as it's used by + * the macros to emit code. + */ + emit_func emitm; + + /* Allocate the reference table for the jumps */ + stream.refs = (u_int *)malloc((nins + 1) * sizeof(u_int), + M_BPFJIT, M_WAITOK); + if (stream.refs == NULL) + return NULL; + + /* Reset the reference table */ + for (i = 0; i < nins + 1; i++) + stream.refs[i] = 0; + + stream.cur_ip = 0; + stream.bpf_pc = 0; + + /* + * the first pass will emit the lengths of the instructions + * to create the reference table + */ + emitm = emit_length; + + pass = 0; + for (;;) { + ins = prog; + + /* create the procedure header */ + PUSH(RBP); + MOVrq(RBP, RSP); + MOVoqd(RBP, -8, ESI); + MOVoqd(RBP, -12, EDX); + PUSH(RBX); + MOVrq(RBX, RDI); + + for (i = 0; i < nins; i++) { + stream.bpf_pc++; + + switch (ins->code) { + default: + return NULL; + + case BPF_RET|BPF_K: + MOVid(EAX, ins->k); + POP(RBX); + LEAVE_RET(); + break; + + case BPF_RET|BPF_A: + POP(RBX); + LEAVE_RET(); + break; + + case BPF_LD|BPF_W|BPF_ABS: + MOVid(ECX, ins->k); + MOVrd(ESI, ECX); + ADDib(ECX, sizeof(int)); + CMPodd(ECX, RBP, -12); + JLEb(5); + ZERO_EAX(); + POP(RBX); + LEAVE_RET(); + MOVobd(EAX, RBX, RSI); + BSWAP(EAX); + break; + + case BPF_LD|BPF_H|BPF_ABS: + ZERO_EAX(); + MOVid(ECX, ins->k); + MOVrd(ESI, ECX); + ADDib(ECX, sizeof(short)); + CMPodd(ECX, RBP, -12); + JLEb(3); + POP(RBX); + LEAVE_RET(); + MOVobw(AX, RBX, RSI); + SWAP_AX(); + break; + + case BPF_LD|BPF_B|BPF_ABS: + ZERO_EAX(); + MOVid(ECX, ins->k); + CMPodd(ECX, RBP, -12); + JLEb(3); + POP(RBX); + LEAVE_RET(); + MOVobb(AL, RBX, RCX); + break; + + case BPF_LD|BPF_W|BPF_LEN: + MOVodd(EAX, RBP, -8); + break; + + case BPF_LDX|BPF_W|BPF_LEN: + MOVodd(EDX, RBP, -8); + break; + + case BPF_LD|BPF_W|BPF_IND: + MOVid(ECX, ins->k); + ADDrd(ECX, EDX); + MOVrd(ESI, ECX); + ADDib(ECX, sizeof(int)); + CMPodd(ECX, RBP, -12); + JLEb(5); + ZERO_EAX(); + POP(RBX); + LEAVE_RET(); + MOVobd(EAX, RBX, RSI); + BSWAP(EAX); + break; + + case BPF_LD|BPF_H|BPF_IND: + ZERO_EAX(); + MOVid(ECX, ins->k); + ADDrd(ECX, EDX); + MOVrd(ESI, ECX); + ADDib(ECX, sizeof(short)); + CMPodd(ECX, RBP, -12); + JLEb(3); + POP(RBX); + LEAVE_RET(); + MOVobw(AX, RBX, RSI); + SWAP_AX(); + break; + + case BPF_LD|BPF_B|BPF_IND: + ZERO_EAX(); + MOVid(ECX, ins->k); + ADDrd(ECX, EDX); + CMPodd(ECX, RBP, -12); + JLEb(3); + POP(RBX); + LEAVE_RET(); + MOVobb(AL, RBX, RCX); + break; + + case BPF_LDX|BPF_MSH|BPF_B: + MOVid(ECX, ins->k); + CMPodd(ECX, RBP, -12); + JLEb(5); + ZERO_EAX(); + POP(RBX); + LEAVE_RET(); + MOVid(EDX, 0); + MOVobb(DL, RBX, RCX); + ANDib(DL, 0xf); + SHLib(EDX, 2); + break; + + case BPF_LD|BPF_IMM: + MOVid(EAX, ins->k); + break; + + case BPF_LDX|BPF_IMM: + MOVid(EDX, ins->k); + break; + + case BPF_LD|BPF_MEM: + MOViq(RCX, (uintptr_t)mem); + MOVid(ESI, ins->k * 4); + MOVobd(EAX, RCX, RSI); + break; + + case BPF_LDX|BPF_MEM: + MOViq(RCX, (uintptr_t)mem); + MOVid(ESI, ins->k * 4); + MOVobd(EDX, RCX, RSI); + break; + + case BPF_ST: + /* + * XXX this command and the following could + * be optimized if the previous instruction + * was already of this type + */ + MOViq(RCX, (uintptr_t)mem); + MOVid(ESI, ins->k * 4); + MOVomd(RCX, RSI, EAX); + break; + + case BPF_STX: + MOViq(RCX, (uintptr_t)mem); + MOVid(ESI, ins->k * 4); + MOVomd(RCX, RSI, EDX); + break; + + case BPF_JMP|BPF_JA: + JMP(stream.refs[stream.bpf_pc + ins->k] - + stream.refs[stream.bpf_pc]); + break; + + case BPF_JMP|BPF_JGT|BPF_K: + CMPid(EAX, ins->k); + /* 5 is the size of the following JMP */ + JG(stream.refs[stream.bpf_pc + ins->jt] - + stream.refs[stream.bpf_pc] + 5 ); + JMP(stream.refs[stream.bpf_pc + ins->jf] - + stream.refs[stream.bpf_pc]); + break; + + case BPF_JMP|BPF_JGE|BPF_K: + CMPid(EAX, ins->k); + JGE(stream.refs[stream.bpf_pc + ins->jt] - + stream.refs[stream.bpf_pc] + 5); + JMP(stream.refs[stream.bpf_pc + ins->jf] - + stream.refs[stream.bpf_pc]); + break; + + case BPF_JMP|BPF_JEQ|BPF_K: + CMPid(EAX, ins->k); + JE(stream.refs[stream.bpf_pc + ins->jt] - + stream.refs[stream.bpf_pc] + 5); + JMP(stream.refs[stream.bpf_pc + ins->jf] - + stream.refs[stream.bpf_pc]); + break; + + case BPF_JMP|BPF_JSET|BPF_K: + MOVrd(ECX, EAX); + ANDid(ECX, ins->k); + JE(stream.refs[stream.bpf_pc + ins->jf] - + stream.refs[stream.bpf_pc] + 5); + JMP(stream.refs[stream.bpf_pc + ins->jt] - + stream.refs[stream.bpf_pc]); + break; + + case BPF_JMP|BPF_JGT|BPF_X: + CMPrd(EAX, EDX); + JA(stream.refs[stream.bpf_pc + ins->jt] - + stream.refs[stream.bpf_pc] + 5); + JMP(stream.refs[stream.bpf_pc + ins->jf] - + stream.refs[stream.bpf_pc]); + break; + + case BPF_JMP|BPF_JGE|BPF_X: + CMPrd(EAX, EDX); + JAE(stream.refs[stream.bpf_pc + ins->jt] - + stream.refs[stream.bpf_pc] + 5); + JMP(stream.refs[stream.bpf_pc + ins->jf] - + stream.refs[stream.bpf_pc]); + break; + + case BPF_JMP|BPF_JEQ|BPF_X: + CMPrd(EAX, EDX); + JE(stream.refs[stream.bpf_pc + ins->jt] - + stream.refs[stream.bpf_pc] + 5); + JMP(stream.refs[stream.bpf_pc + ins->jf] - + stream.refs[stream.bpf_pc]); + break; + + case BPF_JMP|BPF_JSET|BPF_X: + MOVrd(ECX, EAX); + ANDrd(ECX, EDX); + JE(stream.refs[stream.bpf_pc + ins->jf] - + stream.refs[stream.bpf_pc] + 5); + JMP(stream.refs[stream.bpf_pc + ins->jt] - + stream.refs[stream.bpf_pc]); + break; + + case BPF_ALU|BPF_ADD|BPF_X: + ADDrd(EAX, EDX); + break; + + case BPF_ALU|BPF_SUB|BPF_X: + SUBrd(EAX, EDX); + break; + + case BPF_ALU|BPF_MUL|BPF_X: + MOVrd(ECX, EDX); + MULrd(EDX); + MOVrd(EDX, ECX); + break; + + case BPF_ALU|BPF_DIV|BPF_X: + CMPid(EDX, 0); + JNEb(5); + ZERO_EAX(); + POP(RBX); + LEAVE_RET(); + MOVrd(ECX, EDX); + MOVid(EDX, 0); + DIVrd(ECX); + MOVrd(EDX, ECX); + break; + + case BPF_ALU|BPF_AND|BPF_X: + ANDrd(EAX, EDX); + break; + + case BPF_ALU|BPF_OR|BPF_X: + ORrd(EAX, EDX); + break; + + case BPF_ALU|BPF_LSH|BPF_X: + MOVrd(ECX, EDX); + SHL_CLrb(EAX); + break; + + case BPF_ALU|BPF_RSH|BPF_X: + MOVrd(ECX, EDX); + SHR_CLrb(EAX); + break; + + case BPF_ALU|BPF_ADD|BPF_K: + ADD_EAXi(ins->k); + break; + + case BPF_ALU|BPF_SUB|BPF_K: + SUB_EAXi(ins->k); + break; + + case BPF_ALU|BPF_MUL|BPF_K: + MOVrd(ECX, EDX); + MOVid(EDX, ins->k); + MULrd(EDX); + MOVrd(EDX, ECX); + break; + + case BPF_ALU|BPF_DIV|BPF_K: + MOVrd(ECX, EDX); + MOVid(EDX, 0); + MOVid(ESI, ins->k); + DIVrd(ESI); + MOVrd(EDX, ECX); + break; + + case BPF_ALU|BPF_AND|BPF_K: + ANDid(EAX, ins->k); + break; + + case BPF_ALU|BPF_OR|BPF_K: + ORid(EAX, ins->k); + break; + + case BPF_ALU|BPF_LSH|BPF_K: + SHLib(EAX, (ins->k) & 255); + break; + + case BPF_ALU|BPF_RSH|BPF_K: + SHRib(EAX, (ins->k) & 255); + break; + + case BPF_ALU|BPF_NEG: + NEGd(EAX); + break; + + case BPF_MISC|BPF_TAX: + MOVrd(EDX, EAX); + break; + + case BPF_MISC|BPF_TXA: + MOVrd(EAX, EDX); + break; + } + ins++; + } + + pass++; + if (pass == 2) + break; + + stream.ibuf = (char *)malloc(stream.cur_ip, M_BPFJIT, M_WAITOK); + if (stream.ibuf == NULL) { + free(stream.refs, M_BPFJIT); + return NULL; + } + + /* + * modify the reference table to contain the offsets and + * not the lengths of the instructions + */ + for (i = 1; i < nins + 1; i++) + stream.refs[i] += stream.refs[i - 1]; + + /* Reset the counters */ + stream.cur_ip = 0; + stream.bpf_pc = 0; + + /* the second pass creates the actual code */ + emitm = emit_code; + } + + /* + * the reference table is needed only during compilation, + * now we can free it + */ + free(stream.refs, M_BPFJIT); + + return (bpf_filter_func)stream.ibuf; +} diff --git a/sys/amd64/amd64/bpf_jit_machdep.h b/sys/amd64/amd64/bpf_jit_machdep.h new file mode 100644 index 0000000..028d961 --- /dev/null +++ b/sys/amd64/amd64/bpf_jit_machdep.h @@ -0,0 +1,431 @@ +/*- + * Copyright (c) 2002 - 2003 NetGroup, Politecnico di Torino (Italy) + * Copyright (c) 2005 Jung-uk Kim <jkim@FreeBSD.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Politecnico di Torino nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS intERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _BPF_JIT_MACHDEP_H_ +#define _BPF_JIT_MACHDEP_H_ + +/* + * Registers + */ +#define RAX 0 +#define RCX 1 +#define RDX 2 +#define RBX 3 +#define RSP 4 +#define RBP 5 +#define RSI 6 +#define RDI 7 + +#define EAX 0 +#define ECX 1 +#define EDX 2 +#define EBX 3 +#define ESP 4 +#define EBP 5 +#define ESI 6 +#define EDI 7 + +#define AX 0 +#define CX 1 +#define DX 2 +#define BX 3 +#define SP 4 +#define BP 5 +#define SI 6 +#define DI 7 + +#define AL 0 +#define CL 1 +#define DL 2 +#define BL 3 + +/* A stream of native binary code.*/ +typedef struct bpf_bin_stream { + /* Current native instruction pointer. */ + int cur_ip; + + /* + * Current BPF instruction pointer, i.e. position in + * the BPF program reached by the jitter. + */ + int bpf_pc; + + /* Instruction buffer, contains the generated native code. */ + char *ibuf; + + /* Jumps reference table. */ + u_int *refs; +} bpf_bin_stream; + +/* + * Prototype of the emit functions. + * + * Different emit functions are used to create the reference table and + * to generate the actual filtering code. This allows to have simpler + * instruction macros. + * The first parameter is the stream that will receive the data. + * The second one is a variable containing the data. + * The third one is the length, that can be 1, 2, or 4 since it is possible + * to emit a byte, a short, or a word at a time. + */ +typedef void (*emit_func)(bpf_bin_stream *stream, u_int value, u_int n); + +/* + * native Instruction Macros + */ + +/* mov r32,i32 */ +#define MOVid(r32, i32) do { \ + emitm(&stream, (11 << 4) | (1 << 3) | (r32 & 0x7), 1); \ + emitm(&stream, i32, 4); \ +} while (0) + +/* mov r64,i64 */ +#define MOViq(r64, i64) do { \ + emitm(&stream, 0x48, 1); \ + emitm(&stream, (11 << 4) | (1 << 3) | (r64 & 0x7), 1); \ + emitm(&stream, i64, 4); \ + emitm(&stream, (i64 >> 32), 4); \ +} while (0) + +/* mov dr32,sr32 */ +#define MOVrd(dr32, sr32) do { \ + emitm(&stream, (8 << 4) | 3 | (1 << 3), 1); \ + emitm(&stream, \ + (3 << 6) | ((dr32 & 0x7) << 3) | (sr32 & 0x7), 1); \ +} while (0) + +/* mov dr64,sr64 */ +#define MOVrq(dr64, sr64) do { \ + emitm(&stream, 0x48, 1); \ + emitm(&stream, (8 << 4) | 3 | (1 << 3), 1); \ + emitm(&stream, \ + (3 << 6) | ((dr64 & 0x7) << 3) | (sr64 & 0x7), 1); \ +} while (0) + +/* mov dr32,sr32[off] */ +#define MOVodd(dr32, sr32, off) do { \ + emitm(&stream, (8 << 4) | 3 | (1 << 3), 1); \ + emitm(&stream, \ + (1 << 6) | ((dr32 & 0x7) << 3) | (sr32 & 0x7), 1); \ + emitm(&stream, off, 1); \ +} while (0) + +/* mov dr64[off],sr32 */ +#define MOVoqd(dr64, off, sr32) do { \ + emitm(&stream, (8 << 4) | 1 | (1 << 3), 1); \ + emitm(&stream, \ + (1 << 6) | ((sr32 & 0x7) << 3) | (dr64 & 0x7), 1); \ + emitm(&stream, off, 1); \ +} while (0) + +/* mov dr32,sr32[or32] */ +#define MOVobd(dr32, sr32, or32) do { \ + emitm(&stream, (8 << 4) | 3 | (1 << 3), 1); \ + emitm(&stream, ((dr32 & 0x7) << 3) | 4, 1); \ + emitm(&stream, ((or32 & 0x7) << 3) | (sr32 & 0x7), 1); \ +} while (0) + +/* mov dr16,sr32[or32] */ +#define MOVobw(dr32, sr32, or32) do { \ + emitm(&stream, 0x66, 1); \ + emitm(&stream, (8 << 4) | 3 | (1 << 3), 1); \ + emitm(&stream, ((dr32 & 0x7) << 3) | 4, 1); \ + emitm(&stream, ((or32 & 0x7) << 3) | (sr32 & 0x7), 1); \ +} while (0) + +/* mov dr8,sr32[or32] */ +#define MOVobb(dr8, sr32, or32) do { \ + emitm(&stream, 0x8a, 1); \ + emitm(&stream, ((dr8 & 0x7) << 3) | 4, 1); \ + emitm(&stream, ((or32 & 0x7) << 3) | (sr32 & 0x7), 1); \ +} while (0) + +/* mov [dr32][or32],sr32 */ +#define MOVomd(dr32, or32, sr32) do { \ + emitm(&stream, 0x89, 1); \ + emitm(&stream, ((sr32 & 0x7) << 3) | 4, 1); \ + emitm(&stream, ((or32 & 0x7) << 3) | (dr32 & 0x7), 1); \ +} while (0) + +/* bswap dr32 */ +#define BSWAP(dr32) do { \ + emitm(&stream, 0xf, 1); \ + emitm(&stream, (0x19 << 3) | dr32, 1); \ +} while (0) + +/* xchg al,ah */ +#define SWAP_AX() do { \ + emitm(&stream, 0x86, 1); \ + emitm(&stream, 0xc4, 1); \ +} while (0) + +/* push r64 */ +#define PUSH(r64) do { \ + emitm(&stream, (5 << 4) | (0 << 3) | (r64 & 0x7), 1); \ +} while (0) + +/* pop r64 */ +#define POP(r64) do { \ + emitm(&stream, (5 << 4) | (1 << 3) | (r64 & 0x7), 1); \ +} while (0) + +/* leave/ret */ +#define LEAVE_RET() do { \ + emitm(&stream, 0xc9, 1); \ + emitm(&stream, 0xc3, 1); \ +} while (0) + +/* add dr32,sr32 */ +#define ADDrd(dr32, sr32) do { \ + emitm(&stream, 0x03, 1); \ + emitm(&stream, \ + (3 << 6) | ((dr32 & 0x7) << 3) | (sr32 & 0x7), 1); \ +} while (0) + +/* add eax,i32 */ +#define ADD_EAXi(i32) do { \ + emitm(&stream, 0x05, 1); \ + emitm(&stream, i32, 4); \ +} while (0) + +/* add r32,i32 */ +#define ADDid(r32, i32) do { \ + emitm(&stream, 0x81, 1); \ + emitm(&stream, (24 << 3) | r32, 1); \ + emitm(&stream, i32, 4); \ +} while (0) + +/* add r32,i8 */ +#define ADDib(r32, i8) do { \ + emitm(&stream, 0x83, 1); \ + emitm(&stream, (24 << 3) | r32, 1); \ + emitm(&stream, i8, 1); \ +} while (0) + +/* sub dr32,sr32 */ +#define SUBrd(dr32, sr32) do { \ + emitm(&stream, 0x2b, 1); \ + emitm(&stream, \ + (3 << 6) | ((dr32 & 0x7) << 3) | (sr32 & 0x7), 1); \ +} while (0) + +/* sub eax,i32 */ +#define SUB_EAXi(i32) do { \ + emitm(&stream, 0x2d, 1); \ + emitm(&stream, i32, 4); \ +} while (0) + +/* mul r32 */ +#define MULrd(r32) do { \ + emitm(&stream, 0xf7, 1); \ + emitm(&stream, (7 << 5) | (r32 & 0x7), 1); \ +} while (0) + +/* div r32 */ +#define DIVrd(r32) do { \ + emitm(&stream, 0xf7, 1); \ + emitm(&stream, (15 << 4) | (r32 & 0x7), 1); \ +} while (0) + +/* and r8,i8 */ +#define ANDib(r8, i8) do { \ + emitm(&stream, 0x80, 1); \ + emitm(&stream, (7 << 5) | r8, 1); \ + emitm(&stream, i8, 1); \ +} while (0) + +/* and r32,i32 */ +#define ANDid(r32, i32) do { \ + if (r32 == EAX) { \ + emitm(&stream, 0x25, 1); \ + emitm(&stream, i32, 4); \ + } else { \ + emitm(&stream, 0x81, 1); \ + emitm(&stream, (7 << 5) | r32, 1); \ + emitm(&stream, i32, 4); \ + } \ +} while (0) + +/* and dr32,sr32 */ +#define ANDrd(dr32, sr32) do { \ + emitm(&stream, 0x23, 1); \ + emitm(&stream, \ + (3 << 6) | ((dr32 & 0x7) << 3) | (sr32 & 0x7), 1); \ +} while (0) + +/* or dr32,sr32 */ +#define ORrd(dr32, sr32) do { \ + emitm(&stream, 0x0b, 1); \ + emitm(&stream, \ + (3 << 6) | ((dr32 & 0x7) << 3) | (sr32 & 0x7), 1); \ +} while (0) + +/* or r32,i32 */ +#define ORid(r32, i32) do { \ + if (r32 == EAX) { \ + emitm(&stream, 0x0d, 1); \ + emitm(&stream, i32, 4); \ + } else { \ + emitm(&stream, 0x81, 1); \ + emitm(&stream, (25 << 3) | r32, 1); \ + emitm(&stream, i32, 4); \ + } \ +} while (0) + +/* shl r32,i8 */ +#define SHLib(r32, i8) do { \ + emitm(&stream, 0xc1, 1); \ + emitm(&stream, (7 << 5) | (r32 & 0x7), 1); \ + emitm(&stream, i8, 1); \ +} while (0) + +/* shl dr32,cl */ +#define SHL_CLrb(dr32) do { \ + emitm(&stream, 0xd3, 1); \ + emitm(&stream, (7 << 5) | (dr32 & 0x7), 1); \ +} while (0) + +/* shr r32,i8 */ +#define SHRib(r32, i8) do { \ + emitm(&stream, 0xc1, 1); \ + emitm(&stream, (29 << 3) | (r32 & 0x7), 1); \ + emitm(&stream, i8, 1); \ +} while (0) + +/* shr dr32,cl */ +#define SHR_CLrb(dr32) do { \ + emitm(&stream, 0xd3, 1); \ + emitm(&stream, (29 << 3) | (dr32 & 0x7), 1); \ +} while (0) + +/* neg r32 */ +#define NEGd(r32) do { \ + emitm(&stream, 0xf7, 1); \ + emitm(&stream, (27 << 3) | (r32 & 0x7), 1); \ +} while (0) + +/* cmp dr32,sr32[off] */ +#define CMPodd(dr32, sr32, off) do { \ + emitm(&stream, (3 << 4) | 3 | (1 << 3), 1); \ + emitm(&stream, \ + (1 << 6) | ((dr32 & 0x7) << 3) | (sr32 & 0x7), 1); \ + emitm(&stream, off, 1); \ +} while (0) + +/* cmp dr32,sr32 */ +#define CMPrd(dr32, sr32) do { \ + emitm(&stream, 0x3b, 1); \ + emitm(&stream, \ + (3 << 6) | ((dr32 & 0x7) << 3) | (sr32 & 0x7), 1); \ +} while (0) + +/* cmp dr32,i32 */ +#define CMPid(dr32, i32) do { \ + if (dr32 == EAX){ \ + emitm(&stream, 0x3d, 1); \ + emitm(&stream, i32, 4); \ + } else { \ + emitm(&stream, 0x81, 1); \ + emitm(&stream, (0x1f << 3) | (dr32 & 0x7), 1); \ + emitm(&stream, i32, 4); \ + } \ +} while (0) + +/* jne off32 */ +#define JNEb(off8) do { \ + emitm(&stream, 0x75, 1); \ + emitm(&stream, off8, 1); \ +} while (0) + +/* je off32 */ +#define JE(off32) do { \ + emitm(&stream, 0x0f, 1); \ + emitm(&stream, 0x84, 1); \ + emitm(&stream, off32, 4); \ +} while (0) + +/* jle off32 */ +#define JLE(off32) do { \ + emitm(&stream, 0x0f, 1); \ + emitm(&stream, 0x8e, 1); \ + emitm(&stream, off32, 4); \ +} while (0) + +/* jle off8 */ +#define JLEb(off8) do { \ + emitm(&stream, 0x7e, 1); \ + emitm(&stream, off8, 1); \ +} while (0) + +/* ja off32 */ +#define JA(off32) do { \ + emitm(&stream, 0x0f, 1); \ + emitm(&stream, 0x87, 1); \ + emitm(&stream, off32, 4); \ +} while (0) + +/* jae off32 */ +#define JAE(off32) do { \ + emitm(&stream, 0x0f, 1); \ + emitm(&stream, 0x83, 1); \ + emitm(&stream, off32, 4); \ +} while (0) + +/* jg off32 */ +#define JG(off32) do { \ + emitm(&stream, 0x0f, 1); \ + emitm(&stream, 0x8f, 1); \ + emitm(&stream, off32, 4); \ +} while (0) + +/* jge off32 */ +#define JGE(off32) do { \ + emitm(&stream, 0x0f, 1); \ + emitm(&stream, 0x8d, 1); \ + emitm(&stream, off32, 4); \ +} while (0) + +/* jmp off32 */ +#define JMP(off32) do { \ + emitm(&stream, 0xe9, 1); \ + emitm(&stream, off32, 4); \ +} while (0) + +/* xor eax,eax */ +#define ZERO_EAX() do { \ + emitm(&stream, 0x31, 1); \ + emitm(&stream, 0xc0, 1); \ +} while (0) + +#endif /* _BPF_JIT_MACHDEP_H_ */ diff --git a/sys/conf/files b/sys/conf/files index f7efe09..014d269 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -1401,6 +1401,7 @@ libkern/strtoul.c standard libkern/strtouq.c standard libkern/strvalid.c standard net/bpf.c standard +net/bpf_jitter.c optional bpf bpf_jitter net/bpf_filter.c optional bpf | netgraph_bpf net/bridgestp.c optional if_bridge net/bsd_comp.c optional ppp_bsdcomp diff --git a/sys/conf/files.amd64 b/sys/conf/files.amd64 index 084d534..2a302ab 100644 --- a/sys/conf/files.amd64 +++ b/sys/conf/files.amd64 @@ -82,6 +82,7 @@ amd64/amd64/amd64_mem.c optional mem amd64/amd64/atomic.c standard amd64/amd64/autoconf.c standard amd64/amd64/bios.c standard +amd64/amd64/bpf_jit_machdep.c optional bpf bpf_jitter amd64/amd64/busdma_machdep.c standard amd64/amd64/cpu_switch.S standard amd64/amd64/db_disasm.c optional ddb diff --git a/sys/conf/files.i386 b/sys/conf/files.i386 index e57050e..80cd43a 100644 --- a/sys/conf/files.i386 +++ b/sys/conf/files.i386 @@ -241,6 +241,7 @@ i386/i386/atomic.c standard \ i386/i386/autoconf.c standard i386/i386/bios.c standard i386/i386/bioscall.s standard +i386/i386/bpf_jit_machdep.c optional bpf bpf_jitter i386/i386/busdma_machdep.c standard i386/i386/db_disasm.c optional ddb i386/i386/db_interface.c optional ddb diff --git a/sys/conf/options.amd64 b/sys/conf/options.amd64 index 7b115ef..310dbce 100644 --- a/sys/conf/options.amd64 +++ b/sys/conf/options.amd64 @@ -58,3 +58,6 @@ DEV_ATPIC opt_atpic.h # Debugging STOP_NMI opt_cpu.h + +# BPF just-in-time compiler +BPF_JITTER opt_bpf.h diff --git a/sys/conf/options.i386 b/sys/conf/options.i386 index b2a079f..c016c58 100644 --- a/sys/conf/options.i386 +++ b/sys/conf/options.i386 @@ -168,3 +168,6 @@ STOP_NMI opt_cpu.h # XBOX support in the kernel XBOX opt_xbox.h + +# BPF just-in-time compiler +BPF_JITTER opt_bpf.h diff --git a/sys/i386/i386/bpf_jit_machdep.c b/sys/i386/i386/bpf_jit_machdep.c new file mode 100644 index 0000000..0de6196 --- /dev/null +++ b/sys/i386/i386/bpf_jit_machdep.c @@ -0,0 +1,510 @@ +/*- + * Copyright (c) 2002 - 2003 NetGroup, Politecnico di Torino (Italy) + * Copyright (c) 2005 Jung-uk Kim <jkim@FreeBSD.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Politecnico di Torino nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS intERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "opt_bpf.h" + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/malloc.h> + +#include <net/if.h> +#include <net/bpf.h> +#include <net/bpf_jitter.h> + +#include <i386/i386/bpf_jit_machdep.h> + +bpf_filter_func bpf_jit_compile(struct bpf_insn *, u_int, int *); + +/* + * emit routine to update the jump table + */ +static void +emit_length(bpf_bin_stream *stream, u_int value, u_int len) +{ + + (stream->refs)[stream->bpf_pc] += len; + stream->cur_ip += len; +} + +/* + * emit routine to output the actual binary code + */ +static void +emit_code(bpf_bin_stream *stream, u_int value, u_int len) +{ + + switch (len) { + case 1: + stream->ibuf[stream->cur_ip] = (u_char)value; + stream->cur_ip++; + break; + + case 2: + *((u_short *)(stream->ibuf + stream->cur_ip)) = (u_short)value; + stream->cur_ip += 2; + break; + + case 4: + *((u_int *)(stream->ibuf + stream->cur_ip)) = value; + stream->cur_ip += 4; + break; + } + + return; +} + +/* + * Function that does the real stuff + */ +bpf_filter_func +bpf_jit_compile(struct bpf_insn *prog, u_int nins, int *mem) +{ + struct bpf_insn *ins; + u_int i, pass; + bpf_bin_stream stream; + + /* + * NOTE: do not modify the name of this variable, as it's used by + * the macros to emit code. + */ + emit_func emitm; + + /* Allocate the reference table for the jumps */ + stream.refs = (u_int *)malloc((nins + 1) * sizeof(u_int), + M_BPFJIT, M_WAITOK); + if (stream.refs == NULL) + return NULL; + + /* Reset the reference table */ + for (i = 0; i < nins + 1; i++) + stream.refs[i] = 0; + + stream.cur_ip = 0; + stream.bpf_pc = 0; + + /* + * the first pass will emit the lengths of the instructions + * to create the reference table + */ + emitm = emit_length; + + pass = 0; + for (;;) { + ins = prog; + + /* create the procedure header */ + PUSH(EBP); + MOVrd(EBP, ESP); + PUSH(EDI); + PUSH(ESI); + PUSH(EBX); + MOVodd(EBX, EBP, 8); + + for (i = 0; i < nins; i++) { + stream.bpf_pc++; + + switch (ins->code) { + default: + return NULL; + + case BPF_RET|BPF_K: + MOVid(EAX, ins->k); + POP(EBX); + POP(ESI); + POP(EDI); + LEAVE_RET(); + break; + + case BPF_RET|BPF_A: + POP(EBX); + POP(ESI); + POP(EDI); + LEAVE_RET(); + break; + + case BPF_LD|BPF_W|BPF_ABS: + MOVid(ECX, ins->k); + MOVrd(ESI, ECX); + ADDib(ECX, sizeof(int)); + CMPodd(ECX, EBP, 0x10); + JLEb(7); + ZERO_EAX(); + POP(EBX); + POP(ESI); + POP(EDI); + LEAVE_RET(); + MOVobd(EAX, EBX, ESI); + BSWAP(EAX); + break; + + case BPF_LD|BPF_H|BPF_ABS: + ZERO_EAX(); + MOVid(ECX, ins->k); + MOVrd(ESI, ECX); + ADDib(ECX, sizeof(short)); + CMPodd(ECX, EBP, 0x10); + JLEb(5); + POP(EBX); + POP(ESI); + POP(EDI); + LEAVE_RET(); + MOVobw(AX, EBX, ESI); + SWAP_AX(); + break; + + case BPF_LD|BPF_B|BPF_ABS: + ZERO_EAX(); + MOVid(ECX, ins->k); + CMPodd(ECX, EBP, 0x10); + JLEb(5); + POP(EBX); + POP(ESI); + POP(EDI); + LEAVE_RET(); + MOVobb(AL, EBX, ECX); + break; + + case BPF_LD|BPF_W|BPF_LEN: + MOVodd(EAX, EBP, 0xc); + break; + + case BPF_LDX|BPF_W|BPF_LEN: + MOVodd(EDX, EBP, 0xc); + break; + + case BPF_LD|BPF_W|BPF_IND: + MOVid(ECX, ins->k); + ADDrd(ECX, EDX); + MOVrd(ESI, ECX); + ADDib(ECX, sizeof(int)); + CMPodd(ECX, EBP, 0x10); + JLEb(7); + ZERO_EAX(); + POP(EBX); + POP(ESI); + POP(EDI); + LEAVE_RET(); + MOVobd(EAX, EBX, ESI); + BSWAP(EAX); + break; + + case BPF_LD|BPF_H|BPF_IND: + ZERO_EAX(); + MOVid(ECX, ins->k); + ADDrd(ECX, EDX); + MOVrd(ESI, ECX); + ADDib(ECX, sizeof(short)); + CMPodd(ECX, EBP, 0x10); + JLEb(5); + POP(EBX); + POP(ESI); + POP(EDI); + LEAVE_RET(); + MOVobw(AX, EBX, ESI); + SWAP_AX(); + break; + + case BPF_LD|BPF_B|BPF_IND: + ZERO_EAX(); + MOVid(ECX, ins->k); + ADDrd(ECX, EDX); + CMPodd(ECX, EBP, 0x10); + JLEb(5); + POP(EBX); + POP(ESI); + POP(EDI); + LEAVE_RET(); + MOVobb(AL, EBX, ECX); + break; + + case BPF_LDX|BPF_MSH|BPF_B: + MOVid(ECX, ins->k); + CMPodd(ECX, EBP, 0x10); + JLEb(7); + ZERO_EAX(); + POP(EBX); + POP(ESI); + POP(EDI); + LEAVE_RET(); + MOVid(EDX, 0); + MOVobb(DL, EBX, ECX); + ANDib(DL, 0xf); + SHLib(EDX, 2); + break; + + case BPF_LD|BPF_IMM: + MOVid(EAX, ins->k); + break; + + case BPF_LDX|BPF_IMM: + MOVid(EDX, ins->k); + break; + + case BPF_LD|BPF_MEM: + MOVid(ECX, (uintptr_t)mem); + MOVid(ESI, ins->k * 4); + MOVobd(EAX, ECX, ESI); + break; + + case BPF_LDX|BPF_MEM: + MOVid(ECX, (uintptr_t)mem); + MOVid(ESI, ins->k * 4); + MOVobd(EDX, ECX, ESI); + break; + + case BPF_ST: + /* + * XXX this command and the following could + * be optimized if the previous instruction + * was already of this type + */ + MOVid(ECX, (uintptr_t)mem); + MOVid(ESI, ins->k * 4); + MOVomd(ECX, ESI, EAX); + break; + + case BPF_STX: + MOVid(ECX, (uintptr_t)mem); + MOVid(ESI, ins->k * 4); + MOVomd(ECX, ESI, EDX); + break; + + case BPF_JMP|BPF_JA: + JMP(stream.refs[stream.bpf_pc + ins->k] - + stream.refs[stream.bpf_pc]); + break; + + case BPF_JMP|BPF_JGT|BPF_K: + CMPid(EAX, ins->k); + /* 5 is the size of the following JMP */ + JG(stream.refs[stream.bpf_pc + ins->jt] - + stream.refs[stream.bpf_pc] + 5 ); + JMP(stream.refs[stream.bpf_pc + ins->jf] - + stream.refs[stream.bpf_pc]); + break; + + case BPF_JMP|BPF_JGE|BPF_K: + CMPid(EAX, ins->k); + JGE(stream.refs[stream.bpf_pc + ins->jt] - + stream.refs[stream.bpf_pc] + 5); + JMP(stream.refs[stream.bpf_pc + ins->jf] - + stream.refs[stream.bpf_pc]); + break; + + case BPF_JMP|BPF_JEQ|BPF_K: + CMPid(EAX, ins->k); + JE(stream.refs[stream.bpf_pc + ins->jt] - + stream.refs[stream.bpf_pc] + 5); + JMP(stream.refs[stream.bpf_pc + ins->jf] - + stream.refs[stream.bpf_pc]); + break; + + case BPF_JMP|BPF_JSET|BPF_K: + MOVrd(ECX, EAX); + ANDid(ECX, ins->k); + JE(stream.refs[stream.bpf_pc + ins->jf] - + stream.refs[stream.bpf_pc] + 5); + JMP(stream.refs[stream.bpf_pc + ins->jt] - + stream.refs[stream.bpf_pc]); + break; + + case BPF_JMP|BPF_JGT|BPF_X: + CMPrd(EAX, EDX); + JA(stream.refs[stream.bpf_pc + ins->jt] - + stream.refs[stream.bpf_pc] + 5); + JMP(stream.refs[stream.bpf_pc + ins->jf] - + stream.refs[stream.bpf_pc]); + break; + + case BPF_JMP|BPF_JGE|BPF_X: + CMPrd(EAX, EDX); + JAE(stream.refs[stream.bpf_pc + ins->jt] - + stream.refs[stream.bpf_pc] + 5); + JMP(stream.refs[stream.bpf_pc + ins->jf] - + stream.refs[stream.bpf_pc]); + break; + + case BPF_JMP|BPF_JEQ|BPF_X: + CMPrd(EAX, EDX); + JE(stream.refs[stream.bpf_pc + ins->jt] - + stream.refs[stream.bpf_pc] + 5); + JMP(stream.refs[stream.bpf_pc + ins->jf] - + stream.refs[stream.bpf_pc]); + break; + + case BPF_JMP|BPF_JSET|BPF_X: + MOVrd(ECX, EAX); + ANDrd(ECX, EDX); + JE(stream.refs[stream.bpf_pc + ins->jf] - + stream.refs[stream.bpf_pc] + 5); + JMP(stream.refs[stream.bpf_pc + ins->jt] - + stream.refs[stream.bpf_pc]); + break; + + case BPF_ALU|BPF_ADD|BPF_X: + ADDrd(EAX, EDX); + break; + + case BPF_ALU|BPF_SUB|BPF_X: + SUBrd(EAX, EDX); + break; + + case BPF_ALU|BPF_MUL|BPF_X: + MOVrd(ECX, EDX); + MULrd(EDX); + MOVrd(EDX, ECX); + break; + + case BPF_ALU|BPF_DIV|BPF_X: + CMPid(EDX, 0); + JNEb(7); + ZERO_EAX(); + POP(EBX); + POP(ESI); + POP(EDI); + LEAVE_RET(); + MOVrd(ECX, EDX); + MOVid(EDX, 0); + DIVrd(ECX); + MOVrd(EDX, ECX); + break; + + case BPF_ALU|BPF_AND|BPF_X: + ANDrd(EAX, EDX); + break; + + case BPF_ALU|BPF_OR|BPF_X: + ORrd(EAX, EDX); + break; + + case BPF_ALU|BPF_LSH|BPF_X: + MOVrd(ECX, EDX); + SHL_CLrb(EAX); + break; + + case BPF_ALU|BPF_RSH|BPF_X: + MOVrd(ECX, EDX); + SHR_CLrb(EAX); + break; + + case BPF_ALU|BPF_ADD|BPF_K: + ADD_EAXi(ins->k); + break; + + case BPF_ALU|BPF_SUB|BPF_K: + SUB_EAXi(ins->k); + break; + + case BPF_ALU|BPF_MUL|BPF_K: + MOVrd(ECX, EDX); + MOVid(EDX, ins->k); + MULrd(EDX); + MOVrd(EDX, ECX); + break; + + case BPF_ALU|BPF_DIV|BPF_K: + MOVrd(ECX, EDX); + MOVid(EDX, 0); + MOVid(ESI, ins->k); + DIVrd(ESI); + MOVrd(EDX, ECX); + break; + + case BPF_ALU|BPF_AND|BPF_K: + ANDid(EAX, ins->k); + break; + + case BPF_ALU|BPF_OR|BPF_K: + ORid(EAX, ins->k); + break; + + case BPF_ALU|BPF_LSH|BPF_K: + SHLib(EAX, (ins->k) & 255); + break; + + case BPF_ALU|BPF_RSH|BPF_K: + SHRib(EAX, (ins->k) & 255); + break; + + case BPF_ALU|BPF_NEG: + NEGd(EAX); + break; + + case BPF_MISC|BPF_TAX: + MOVrd(EDX, EAX); + break; + + case BPF_MISC|BPF_TXA: + MOVrd(EAX, EDX); + break; + } + ins++; + } + + pass++; + if (pass == 2) + break; + + stream.ibuf = (char *)malloc(stream.cur_ip, M_BPFJIT, M_WAITOK); + if (stream.ibuf == NULL) { + free(stream.refs, M_BPFJIT); + return NULL; + } + + /* + * modify the reference table to contain the offsets and + * not the lengths of the instructions + */ + for (i = 1; i < nins + 1; i++) + stream.refs[i] += stream.refs[i - 1]; + + /* Reset the counters */ + stream.cur_ip = 0; + stream.bpf_pc = 0; + + /* the second pass creates the actual code */ + emitm = emit_code; + } + + /* + * the reference table is needed only during compilation, + * now we can free it + */ + free(stream.refs, M_BPFJIT); + + return (bpf_filter_func)stream.ibuf; +} diff --git a/sys/i386/i386/bpf_jit_machdep.h b/sys/i386/i386/bpf_jit_machdep.h new file mode 100644 index 0000000..5f51938 --- /dev/null +++ b/sys/i386/i386/bpf_jit_machdep.h @@ -0,0 +1,398 @@ +/*- + * Copyright (c) 2002 - 2003 NetGroup, Politecnico di Torino (Italy) + * Copyright (c) 2005 Jung-uk Kim <jkim@FreeBSD.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Politecnico di Torino nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS intERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _BPF_JIT_MACHDEP_H_ +#define _BPF_JIT_MACHDEP_H_ + +/* + * Registers + */ +#define EAX 0 +#define ECX 1 +#define EDX 2 +#define EBX 3 +#define ESP 4 +#define EBP 5 +#define ESI 6 +#define EDI 7 + +#define AX 0 +#define CX 1 +#define DX 2 +#define BX 3 +#define SP 4 +#define BP 5 +#define SI 6 +#define DI 7 + +#define AL 0 +#define CL 1 +#define DL 2 +#define BL 3 + +/* A stream of native binary code.*/ +typedef struct bpf_bin_stream { + /* Current native instruction pointer. */ + int cur_ip; + + /* + * Current BPF instruction pointer, i.e. position in + * the BPF program reached by the jitter. + */ + int bpf_pc; + + /* Instruction buffer, contains the generated native code. */ + char *ibuf; + + /* Jumps reference table. */ + u_int *refs; +} bpf_bin_stream; + +/* + * Prototype of the emit functions. + * + * Different emit functions are used to create the reference table and + * to generate the actual filtering code. This allows to have simpler + * instruction macros. + * The first parameter is the stream that will receive the data. + * The second one is a variable containing the data. + * The third one is the length, that can be 1, 2, or 4 since it is possible + * to emit a byte, a short, or a word at a time. + */ +typedef void (*emit_func)(bpf_bin_stream *stream, u_int value, u_int n); + +/* + * native Instruction Macros + */ + +/* mov r32,i32 */ +#define MOVid(r32, i32) do { \ + emitm(&stream, (11 << 4) | (1 << 3) | (r32 & 0x7), 1); \ + emitm(&stream, i32, 4); \ +} while (0) + +/* mov dr32,sr32 */ +#define MOVrd(dr32, sr32) do { \ + emitm(&stream, (8 << 4) | 3 | (1 << 3), 1); \ + emitm(&stream, \ + (3 << 6) | ((dr32 & 0x7) << 3) | (sr32 & 0x7), 1); \ +} while (0) + +/* mov dr32,sr32[off] */ +#define MOVodd(dr32, sr32, off) do { \ + emitm(&stream, (8 << 4) | 3 | (1 << 3), 1); \ + emitm(&stream, \ + (1 << 6) | ((dr32 & 0x7) << 3) | (sr32 & 0x7), 1); \ + emitm(&stream, off, 1); \ +} while (0) + +/* mov dr32,sr32[or32] */ +#define MOVobd(dr32, sr32, or32) do { \ + emitm(&stream, (8 << 4) | 3 | (1 << 3), 1); \ + emitm(&stream, ((dr32 & 0x7) << 3) | 4, 1); \ + emitm(&stream, ((or32 & 0x7) << 3) | (sr32 & 0x7), 1); \ +} while (0) + +/* mov dr16,sr32[or32] */ +#define MOVobw(dr32, sr32, or32) do { \ + emitm(&stream, 0x66, 1); \ + emitm(&stream, (8 << 4) | 3 | (1 << 3), 1); \ + emitm(&stream, ((dr32 & 0x7) << 3) | 4, 1); \ + emitm(&stream, ((or32 & 0x7) << 3) | (sr32 & 0x7), 1); \ +} while (0) + +/* mov dr8,sr32[or32] */ +#define MOVobb(dr8, sr32, or32) do { \ + emitm(&stream, 0x8a, 1); \ + emitm(&stream, ((dr8 & 0x7) << 3) | 4, 1); \ + emitm(&stream, ((or32 & 0x7) << 3) | (sr32 & 0x7), 1); \ +} while (0) + +/* mov [dr32][or32],sr32 */ +#define MOVomd(dr32, or32, sr32) do { \ + emitm(&stream, 0x89, 1); \ + emitm(&stream, ((sr32 & 0x7) << 3) | 4, 1); \ + emitm(&stream, ((or32 & 0x7) << 3) | (dr32 & 0x7), 1); \ +} while (0) + +/* bswap dr32 */ +#define BSWAP(dr32) do { \ + emitm(&stream, 0xf, 1); \ + emitm(&stream, (0x19 << 3) | dr32, 1); \ +} while (0) + +/* xchg al,ah */ +#define SWAP_AX() do { \ + emitm(&stream, 0x86, 1); \ + emitm(&stream, 0xc4, 1); \ +} while (0) + +/* push r32 */ +#define PUSH(r32) do { \ + emitm(&stream, (5 << 4) | (0 << 3) | (r32 & 0x7), 1); \ +} while (0) + +/* pop r32 */ +#define POP(r32) do { \ + emitm(&stream, (5 << 4) | (1 << 3) | (r32 & 0x7), 1); \ +} while (0) + +/* leave/ret */ +#define LEAVE_RET() do { \ + emitm(&stream, 0xc9, 1); \ + emitm(&stream, 0xc3, 1); \ +} while (0) + +/* add dr32,sr32 */ +#define ADDrd(dr32, sr32) do { \ + emitm(&stream, 0x03, 1); \ + emitm(&stream, \ + (3 << 6) | ((dr32 & 0x7) << 3) | (sr32 & 0x7), 1); \ +} while (0) + +/* add eax,i32 */ +#define ADD_EAXi(i32) do { \ + emitm(&stream, 0x05, 1); \ + emitm(&stream, i32, 4); \ +} while (0) + +/* add r32,i32 */ +#define ADDid(r32, i32) do { \ + emitm(&stream, 0x81, 1); \ + emitm(&stream, (24 << 3) | r32, 1); \ + emitm(&stream, i32, 4); \ +} while (0) + +/* add r32,i8 */ +#define ADDib(r32, i8) do { \ + emitm(&stream, 0x83, 1); \ + emitm(&stream, (24 << 3) | r32, 1); \ + emitm(&stream, i8, 1); \ +} while (0) + +/* sub dr32,sr32 */ +#define SUBrd(dr32, sr32) do { \ + emitm(&stream, 0x2b, 1); \ + emitm(&stream, \ + (3 << 6) | ((dr32 & 0x7) << 3) | (sr32 & 0x7), 1); \ +} while (0) + +/* sub eax,i32 */ +#define SUB_EAXi(i32) do { \ + emitm(&stream, 0x2d, 1); \ + emitm(&stream, i32, 4); \ +} while (0) + +/* mul r32 */ +#define MULrd(r32) do { \ + emitm(&stream, 0xf7, 1); \ + emitm(&stream, (7 << 5) | (r32 & 0x7), 1); \ +} while (0) + +/* div r32 */ +#define DIVrd(r32) do { \ + emitm(&stream, 0xf7, 1); \ + emitm(&stream, (15 << 4) | (r32 & 0x7), 1); \ +} while (0) + +/* and r8,i8 */ +#define ANDib(r8, i8) do { \ + emitm(&stream, 0x80, 1); \ + emitm(&stream, (7 << 5) | r8, 1); \ + emitm(&stream, i8, 1); \ +} while (0) + +/* and r32,i32 */ +#define ANDid(r32, i32) do { \ + if (r32 == EAX) { \ + emitm(&stream, 0x25, 1); \ + emitm(&stream, i32, 4); \ + } else { \ + emitm(&stream, 0x81, 1); \ + emitm(&stream, (7 << 5) | r32, 1); \ + emitm(&stream, i32, 4); \ + } \ +} while (0) + +/* and dr32,sr32 */ +#define ANDrd(dr32, sr32) do { \ + emitm(&stream, 0x23, 1); \ + emitm(&stream, \ + (3 << 6) | ((dr32 & 0x7) << 3) | (sr32 & 0x7), 1); \ +} while (0) + +/* or dr32,sr32 */ +#define ORrd(dr32, sr32) do { \ + emitm(&stream, 0x0b, 1); \ + emitm(&stream, \ + (3 << 6) | ((dr32 & 0x7) << 3) | (sr32 & 0x7), 1); \ +} while (0) + +/* or r32,i32 */ +#define ORid(r32, i32) do { \ + if (r32 == EAX) { \ + emitm(&stream, 0x0d, 1); \ + emitm(&stream, i32, 4); \ + } else { \ + emitm(&stream, 0x81, 1); \ + emitm(&stream, (25 << 3) | r32, 1); \ + emitm(&stream, i32, 4); \ + } \ +} while (0) + +/* shl r32,i8 */ +#define SHLib(r32, i8) do { \ + emitm(&stream, 0xc1, 1); \ + emitm(&stream, (7 << 5) | (r32 & 0x7), 1); \ + emitm(&stream, i8, 1); \ +} while (0) + +/* shl dr32,cl */ +#define SHL_CLrb(dr32) do { \ + emitm(&stream, 0xd3, 1); \ + emitm(&stream, (7 << 5) | (dr32 & 0x7), 1); \ +} while (0) + +/* shr r32,i8 */ +#define SHRib(r32, i8) do { \ + emitm(&stream, 0xc1, 1); \ + emitm(&stream, (29 << 3) | (r32 & 0x7), 1); \ + emitm(&stream, i8, 1); \ +} while (0) + +/* shr dr32,cl */ +#define SHR_CLrb(dr32) do { \ + emitm(&stream, 0xd3, 1); \ + emitm(&stream, (29 << 3) | (dr32 & 0x7), 1); \ +} while (0) + +/* neg r32 */ +#define NEGd(r32) do { \ + emitm(&stream, 0xf7, 1); \ + emitm(&stream, (27 << 3) | (r32 & 0x7), 1); \ +} while (0) + +/* cmp dr32,sr32[off] */ +#define CMPodd(dr32, sr32, off) do { \ + emitm(&stream, (3 << 4) | 3 | (1 << 3), 1); \ + emitm(&stream, \ + (1 << 6) | ((dr32 & 0x7) << 3) | (sr32 & 0x7), 1); \ + emitm(&stream, off, 1); \ +} while (0) + +/* cmp dr32,sr32 */ +#define CMPrd(dr32, sr32) do { \ + emitm(&stream, 0x3b, 1); \ + emitm(&stream, \ + (3 << 6) | ((dr32 & 0x7) << 3) | (sr32 & 0x7), 1); \ +} while (0) + +/* cmp dr32,i32 */ +#define CMPid(dr32, i32) do { \ + if (dr32 == EAX){ \ + emitm(&stream, 0x3d, 1); \ + emitm(&stream, i32, 4); \ + } else { \ + emitm(&stream, 0x81, 1); \ + emitm(&stream, (0x1f << 3) | (dr32 & 0x7), 1); \ + emitm(&stream, i32, 4); \ + } \ +} while (0) + +/* jne off32 */ +#define JNEb(off8) do { \ + emitm(&stream, 0x75, 1); \ + emitm(&stream, off8, 1); \ +} while (0) + +/* je off32 */ +#define JE(off32) do { \ + emitm(&stream, 0x0f, 1); \ + emitm(&stream, 0x84, 1); \ + emitm(&stream, off32, 4); \ +} while (0) + +/* jle off32 */ +#define JLE(off32) do { \ + emitm(&stream, 0x0f, 1); \ + emitm(&stream, 0x8e, 1); \ + emitm(&stream, off32, 4); \ +} while (0) + +/* jle off8 */ +#define JLEb(off8) do { \ + emitm(&stream, 0x7e, 1); \ + emitm(&stream, off8, 1); \ +} while (0) + +/* ja off32 */ +#define JA(off32) do { \ + emitm(&stream, 0x0f, 1); \ + emitm(&stream, 0x87, 1); \ + emitm(&stream, off32, 4); \ +} while (0) + +/* jae off32 */ +#define JAE(off32) do { \ + emitm(&stream, 0x0f, 1); \ + emitm(&stream, 0x83, 1); \ + emitm(&stream, off32, 4); \ +} while (0) + +/* jg off32 */ +#define JG(off32) do { \ + emitm(&stream, 0x0f, 1); \ + emitm(&stream, 0x8f, 1); \ + emitm(&stream, off32, 4); \ +} while (0) + +/* jge off32 */ +#define JGE(off32) do { \ + emitm(&stream, 0x0f, 1); \ + emitm(&stream, 0x8d, 1); \ + emitm(&stream, off32, 4); \ +} while (0) + +/* jmp off32 */ +#define JMP(off32) do { \ + emitm(&stream, 0xe9, 1); \ + emitm(&stream, off32, 4); \ +} while (0) + +/* xor eax,eax */ +#define ZERO_EAX() do { \ + emitm(&stream, 0x31, 1); \ + emitm(&stream, 0xc0, 1); \ +} while (0) + +#endif /* _BPF_JIT_MACHDEP_H_ */ diff --git a/sys/net/bpf.c b/sys/net/bpf.c index d2c2d51..5ffcb00 100644 --- a/sys/net/bpf.c +++ b/sys/net/bpf.c @@ -65,6 +65,9 @@ #include <net/if.h> #include <net/bpf.h> +#ifdef BPF_JITTER +#include <net/bpf_jitter.h> +#endif #include <net/bpfdesc.h> #include <netinet/in.h> @@ -126,6 +129,12 @@ SYSCTL_INT(_net_bpf, OID_AUTO, maxinsns, CTLFLAG_RW, &bpf_maxinsns, 0, "Maximum bpf program instructions"); SYSCTL_NODE(_net_bpf, OID_AUTO, stats, CTLFLAG_RW, bpf_stats_sysctl, "bpf statistics portal"); +#ifdef BPF_JITTER +SYSCTL_NODE(_net_bpf, OID_AUTO, jitter, CTLFLAG_RW, 0, "bpf jitter sysctl"); +static int bpf_jitter_enable = 1; +SYSCTL_INT(_net_bpf_jitter, OID_AUTO, enable, CTLFLAG_RW, + &bpf_jitter_enable, 0, "bpf JIT compiler"); +#endif static d_open_t bpfopen; static d_close_t bpfclose; @@ -1017,13 +1026,22 @@ bpf_setf(d, fp, cmd) { struct bpf_insn *fcode, *old; u_int wfilter, flen, size; +#if BPF_JITTER + bpf_jit_filter *ofunc; +#endif if (cmd == BIOCSETWF) { old = d->bd_wfilter; wfilter = 1; +#if BPF_JITTER + ofunc = NULL; +#endif } else { wfilter = 0; old = d->bd_rfilter; +#if BPF_JITTER + ofunc = d->bd_bfilter; +#endif } if (fp->bf_insns == NULL) { if (fp->bf_len != 0) @@ -1031,12 +1049,20 @@ bpf_setf(d, fp, cmd) BPFD_LOCK(d); if (wfilter) d->bd_wfilter = NULL; - else + else { d->bd_rfilter = NULL; +#if BPF_JITTER + d->bd_bfilter = NULL; +#endif + } reset_d(d); BPFD_UNLOCK(d); if (old != NULL) free((caddr_t)old, M_BPF); +#if BPF_JITTER + if (ofunc != NULL) + bpf_destroy_jit_filter(ofunc); +#endif return (0); } flen = fp->bf_len; @@ -1050,12 +1076,20 @@ bpf_setf(d, fp, cmd) BPFD_LOCK(d); if (wfilter) d->bd_wfilter = fcode; - else + else { d->bd_rfilter = fcode; +#if BPF_JITTER + d->bd_bfilter = bpf_jitter(fcode, flen); +#endif + } reset_d(d); BPFD_UNLOCK(d); if (old != NULL) free((caddr_t)old, M_BPF); +#if BPF_JITTER + if (ofunc != NULL) + bpf_destroy_jit_filter(ofunc); +#endif return (0); } @@ -1255,6 +1289,11 @@ bpf_tap(bp, pkt, pktlen) LIST_FOREACH(d, &bp->bif_dlist, bd_next) { BPFD_LOCK(d); ++d->bd_rcount; +#ifdef BPF_JITTER + if (bpf_jitter_enable != 0 && d->bd_bfilter != NULL) + slen = (*(d->bd_bfilter->func))(pkt, pktlen, pktlen); + else +#endif slen = bpf_filter(d->bd_rfilter, pkt, pktlen, pktlen); if (slen != 0) { d->bd_fcount++; @@ -1321,6 +1360,14 @@ bpf_mtap(bp, m) continue; BPFD_LOCK(d); ++d->bd_rcount; +#ifdef BPF_JITTER + /* XXX We cannot handle multiple mbufs. */ + if (bpf_jitter_enable != 0 && d->bd_bfilter != NULL && + m->m_next == NULL) + slen = (*(d->bd_bfilter->func))(mtod(m, u_char *), + pktlen, pktlen); + else +#endif slen = bpf_filter(d->bd_rfilter, (u_char *)m, pktlen, 0); if (slen != 0) { d->bd_fcount++; @@ -1506,8 +1553,12 @@ bpf_freed(d) if (d->bd_fbuf != NULL) free(d->bd_fbuf, M_BPF); } - if (d->bd_rfilter) + if (d->bd_rfilter) { free((caddr_t)d->bd_rfilter, M_BPF); +#ifdef BPF_JITTER + bpf_destroy_jit_filter(d->bd_bfilter); +#endif + } if (d->bd_wfilter) free((caddr_t)d->bd_wfilter, M_BPF); mtx_destroy(&d->bd_mtx); diff --git a/sys/net/bpf_jitter.c b/sys/net/bpf_jitter.c new file mode 100644 index 0000000..26a57fc --- /dev/null +++ b/sys/net/bpf_jitter.c @@ -0,0 +1,85 @@ +/*- + * Copyright (c) 2002 - 2003 NetGroup, Politecnico di Torino (Italy) + * Copyright (c) 2005 Jung-uk Kim <jkim@FreeBSD.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Politecnico di Torino nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS intERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "opt_bpf.h" + +#include <sys/param.h> +#include <sys/kernel.h> +#include <sys/malloc.h> +#include <sys/mbuf.h> + +#include <net/bpf.h> +#include <net/bpf_jitter.h> + +MALLOC_DEFINE(M_BPFJIT, "BPF_JIT", "BPF JIT compiler"); + +bpf_filter_func bpf_jit_compile(struct bpf_insn *, u_int, int *); + +bpf_jit_filter * +bpf_jitter(struct bpf_insn *fp, int nins) +{ + bpf_jit_filter *filter; + + /* Allocate the filter structure */ + filter = (struct bpf_jit_filter *)malloc(sizeof(struct bpf_jit_filter), + M_BPFJIT, M_WAITOK); + if (filter == NULL) + return NULL; + + /* Allocate the filter's memory */ + filter->mem = (int *)malloc(BPF_MEMWORDS * sizeof(int), + M_BPFJIT, M_WAITOK); + if (filter->mem == NULL) { + free(filter, M_BPFJIT); + return NULL; + } + + /* Create the binary */ + if ((filter->func = bpf_jit_compile(fp, nins, filter->mem)) == NULL) { + free(filter->mem, M_BPFJIT); + free(filter, M_BPFJIT); + return NULL; + } + + return filter; +} + +void +bpf_destroy_jit_filter(bpf_jit_filter *filter) +{ + + free(filter->mem, M_BPFJIT); + free(filter->func, M_BPFJIT); + free(filter, M_BPFJIT); +} diff --git a/sys/net/bpf_jitter.h b/sys/net/bpf_jitter.h new file mode 100644 index 0000000..0ae64f9 --- /dev/null +++ b/sys/net/bpf_jitter.h @@ -0,0 +1,80 @@ +/*- + * Copyright (c) 2002 - 2003 NetGroup, Politecnico di Torino (Italy) + * Copyright (c) 2005 Jung-uk Kim <jkim@FreeBSD.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Politecnico di Torino nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS intERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _NET_BPF_JITTER_H_ +#define _NET_BPF_JITTER_H_ + +MALLOC_DECLARE(M_BPFJIT); + +/* + * Prototype of a filtering function created by the jitter. + * + * The syntax and the meaning of the parameters is analogous to the one of + * bpf_filter(). Notice that the filter is not among the parameters because + * it is hardwired in the function. + */ +typedef u_int (*bpf_filter_func)(u_char *, u_int, u_int); + +/* Structure describing a native filtering program created by the jitter. */ +typedef struct bpf_jit_filter { + /* The native filtering binary, in the form of a bpf_filter_func. */ + bpf_filter_func func; + + int *mem; +} bpf_jit_filter; + +/* + * BPF jitter, builds a machine function from a BPF program. + * + * param fp The BPF pseudo-assembly filter that will be translated + * into native code. + * param nins Number of instructions of the input filter. + * return The bpf_jit_filter structure containing the native filtering + * binary. + * + * bpf_jitter allocates the buffers for the new native filter and + * then translates the program pointed by fp calling bpf_jit_compile(). + */ +bpf_jit_filter *bpf_jitter(struct bpf_insn *fp, int nins); + +/* + * Deletes a filtering function that was previously created by bpf_jitter(). + * + * param filter The filter to destroy. + * + * This function frees the variuos buffers (code, memory, etc.) associated + * with a filtering function. + */ +void bpf_destroy_jit_filter(bpf_jit_filter *filter); + +#endif /* _NET_BPF_JITTER_H_ */ diff --git a/sys/net/bpfdesc.h b/sys/net/bpfdesc.h index d2cb985..3de11d8 100644 --- a/sys/net/bpfdesc.h +++ b/sys/net/bpfdesc.h @@ -71,6 +71,9 @@ struct bpf_d { u_long bd_rtout; /* Read timeout in 'ticks' */ struct bpf_insn *bd_rfilter; /* read filter code */ struct bpf_insn *bd_wfilter; /* write filter code */ +#ifdef BPF_JITTER + bpf_jit_filter *bd_bfilter; /* binary filter code */ +#endif u_long bd_rcount; /* number of packets received */ u_long bd_dcount; /* number of packets dropped */ |