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