Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys Add BPF JIT compiler, currently supporting amd64 and i38...
details: https://anonhg.NetBSD.org/src/rev/32409045624d
branches: trunk
changeset: 780652:32409045624d
user: rmind <rmind%NetBSD.org@localhost>
date: Wed Aug 01 23:24:28 2012 +0000
description:
Add BPF JIT compiler, currently supporting amd64 and i386. Code obtained
from FreeBSD. Also, make few BPF fixes and simplifications while here.
Note that bpf_jit_enable is false for now.
OK dyoung@, some feedback from matt@
diffstat:
sys/arch/amd64/amd64/bpf_jit_machdep.c | 657 +++++++++++++++++++++++++++++++
sys/arch/amd64/amd64/bpf_jit_machdep.h | 485 +++++++++++++++++++++++
sys/arch/amd64/conf/files.amd64 | 3 +-
sys/arch/amd64/conf/std.amd64 | 3 +-
sys/arch/i386/conf/files.i386 | 3 +-
sys/arch/i386/conf/std.i386 | 5 +-
sys/arch/i386/i386/bpf_jit_machdep.c | 686 +++++++++++++++++++++++++++++++++
sys/arch/i386/i386/bpf_jit_machdep.h | 430 ++++++++++++++++++++
sys/conf/files | 4 +-
sys/modules/bpf/Makefile | 14 +-
sys/net/bpf.c | 192 +++++----
sys/net/bpf_filter.c | 35 +-
sys/net/bpf_jit.c | 142 ++++++
sys/net/bpf_jit.h | 79 +++
sys/net/bpfdesc.h | 4 +-
15 files changed, 2631 insertions(+), 111 deletions(-)
diffs (truncated from 3092 to 300 lines):
diff -r 79eebe249559 -r 32409045624d sys/arch/amd64/amd64/bpf_jit_machdep.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/arch/amd64/amd64/bpf_jit_machdep.c Wed Aug 01 23:24:28 2012 +0000
@@ -0,0 +1,657 @@
+/* $NetBSD: bpf_jit_machdep.c,v 1.1 2012/08/01 23:24:28 rmind Exp $ */
+
+/*-
+ * Copyright (C) 2002-2003 NetGroup, Politecnico di Torino (Italy)
+ * Copyright (C) 2005-2009 Jung-uk Kim <jkim%FreeBSD.org@localhost>
+ * 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: src/sys/amd64/amd64/bpf_jit_machdep.c,
+ * v 1.22 2010/04/22 23:47:19 jkim Exp $
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: bpf_jit_machdep.c,v 1.1 2012/08/01 23:24:28 rmind Exp $");
+
+#ifdef _KERNEL
+#if defined(_KERNEL_OPT)
+#include "opt_bpf.h"
+#endif
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/malloc.h>
+#include <net/if.h>
+#else
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/param.h>
+#endif
+
+#include <sys/types.h>
+
+#include <net/bpf.h>
+#include <net/bpf_jit.h>
+
+#include <amd64/amd64/bpf_jit_machdep.h>
+
+bpf_filter_func bpf_jit_compile(struct bpf_insn *, u_int, size_t *);
+
+/*
+ * Emit routine to update the jump table.
+ */
+static void
+emit_length(bpf_bin_stream *stream, __unused u_int value, u_int len)
+{
+
+ if (stream->refs != NULL)
+ (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;
+ }
+}
+
+/*
+ * Scan the filter program and find possible optimization.
+ */
+static int
+bpf_jit_optimize(struct bpf_insn *prog, u_int nins)
+{
+ int flags;
+ u_int i;
+
+ /* Do we return immediately? */
+ if (BPF_CLASS(prog[0].code) == BPF_RET)
+ return (BPF_JIT_FRET);
+
+ for (flags = 0, i = 0; i < nins; i++) {
+ switch (prog[i].code) {
+ case BPF_LD|BPF_W|BPF_ABS:
+ case BPF_LD|BPF_H|BPF_ABS:
+ case BPF_LD|BPF_B|BPF_ABS:
+ case BPF_LD|BPF_W|BPF_IND:
+ case BPF_LD|BPF_H|BPF_IND:
+ case BPF_LD|BPF_B|BPF_IND:
+ case BPF_LDX|BPF_MSH|BPF_B:
+ flags |= BPF_JIT_FPKT;
+ break;
+ case BPF_LD|BPF_MEM:
+ case BPF_LDX|BPF_MEM:
+ case BPF_ST:
+ case BPF_STX:
+ flags |= BPF_JIT_FMEM;
+ break;
+ case BPF_LD|BPF_W|BPF_LEN:
+ case BPF_LDX|BPF_W|BPF_LEN:
+ flags |= BPF_JIT_FLEN;
+ break;
+ case BPF_JMP|BPF_JA:
+ case BPF_JMP|BPF_JGT|BPF_K:
+ case BPF_JMP|BPF_JGE|BPF_K:
+ case BPF_JMP|BPF_JEQ|BPF_K:
+ case BPF_JMP|BPF_JSET|BPF_K:
+ case BPF_JMP|BPF_JGT|BPF_X:
+ case BPF_JMP|BPF_JGE|BPF_X:
+ case BPF_JMP|BPF_JEQ|BPF_X:
+ case BPF_JMP|BPF_JSET|BPF_X:
+ flags |= BPF_JIT_FJMP;
+ break;
+ }
+ if (flags == BPF_JIT_FLAG_ALL)
+ break;
+ }
+
+ return (flags);
+}
+
+/*
+ * Function that does the real stuff.
+ */
+bpf_filter_func
+bpf_jit_compile(struct bpf_insn *prog, u_int nins, size_t *size)
+{
+ bpf_bin_stream stream;
+ struct bpf_insn *ins;
+ int flags, fret, fpkt, fmem, fjmp, flen;
+ u_int i, pass;
+
+ /*
+ * NOTE: Do not modify the name of this variable, as it's used by
+ * the macros to emit code.
+ */
+ emit_func emitm;
+
+ flags = bpf_jit_optimize(prog, nins);
+ fret = (flags & BPF_JIT_FRET) != 0;
+ fpkt = (flags & BPF_JIT_FPKT) != 0;
+ fmem = (flags & BPF_JIT_FMEM) != 0;
+ fjmp = (flags & BPF_JIT_FJMP) != 0;
+ flen = (flags & BPF_JIT_FLEN) != 0;
+
+ if (fret)
+ nins = 1;
+
+ memset(&stream, 0, sizeof(stream));
+
+ /* Allocate the reference table for the jumps. */
+ if (fjmp) {
+#ifdef _KERNEL
+ stream.refs = malloc((nins + 1) * sizeof(u_int), M_TEMP,
+ M_NOWAIT | M_ZERO);
+#else
+ stream.refs = calloc(nins + 1, sizeof(u_int));
+#endif
+ if (stream.refs == NULL)
+ return (NULL);
+ }
+
+ /*
+ * The first pass will emit the lengths of the instructions
+ * to create the reference table.
+ */
+ emitm = emit_length;
+
+ for (pass = 0; pass < 2; pass++) {
+ ins = prog;
+
+ /* Create the procedure header. */
+ if (fmem) {
+ PUSH(RBP);
+ MOVrq(RSP, RBP);
+ SUBib(BPF_MEMWORDS * sizeof(uint32_t), RSP);
+ }
+ if (flen)
+ MOVrd2(ESI, R9D);
+ if (fpkt) {
+ MOVrq2(RDI, R8);
+ MOVrd(EDX, EDI);
+ }
+
+ for (i = 0; i < nins; i++) {
+ stream.bpf_pc++;
+
+ switch (ins->code) {
+ default:
+#ifdef _KERNEL
+ return (NULL);
+#else
+ abort();
+#endif
+
+ case BPF_RET|BPF_K:
+ MOVid(ins->k, EAX);
+ if (fmem)
+ LEAVE();
+ RET();
+ break;
+
+ case BPF_RET|BPF_A:
+ if (fmem)
+ LEAVE();
+ RET();
+ break;
+
+ case BPF_LD|BPF_W|BPF_ABS:
+ MOVid(ins->k, ESI);
+ CMPrd(EDI, ESI);
+ JAb(12);
+ MOVrd(EDI, ECX);
+ SUBrd(ESI, ECX);
+ CMPid(sizeof(int32_t), ECX);
+ if (fmem) {
+ JAEb(4);
+ ZEROrd(EAX);
+ LEAVE();
+ } else {
+ JAEb(3);
+ ZEROrd(EAX);
+ }
+ RET();
+ MOVrq3(R8, RCX);
+ MOVobd(RCX, RSI, EAX);
+ BSWAP(EAX);
+ break;
+
+ case BPF_LD|BPF_H|BPF_ABS:
+ ZEROrd(EAX);
+ MOVid(ins->k, ESI);
+ CMPrd(EDI, ESI);
+ JAb(12);
+ MOVrd(EDI, ECX);
+ SUBrd(ESI, ECX);
+ CMPid(sizeof(int16_t), ECX);
+ if (fmem) {
+ JAEb(2);
+ LEAVE();
+ } else
+ JAEb(1);
+ RET();
+ MOVrq3(R8, RCX);
+ MOVobw(RCX, RSI, AX);
+ SWAP_AX();
+ break;
+
+ case BPF_LD|BPF_B|BPF_ABS:
+ ZEROrd(EAX);
+ MOVid(ins->k, ESI);
+ CMPrd(EDI, ESI);
+ if (fmem) {
+ JBb(2);
+ LEAVE();
+ } else
+ JBb(1);
+ RET();
+ MOVrq3(R8, RCX);
+ MOVobb(RCX, RSI, AL);
+ break;
+
+ case BPF_LD|BPF_W|BPF_LEN:
Home |
Main Index |
Thread Index |
Old Index