Implement BPF_COP/BPF_COPX instructions in the misc category (BPF_MISC)

which add a capability to call external functions in a predetermined way.

It can be thought as a BPF "coprocessor" -- a generic mechanism to offload
more complex packet inspection operations.  There is no default coprocessor
and this functionality is not targeted to the /dev/bpf.  This is primarily
targeted to the kernel subsystems, therefore there is no way to set a custom
coprocessor at the userlevel.

Discussed on: tech-net@
OK: core@
This commit is contained in:
rmind 2013-08-29 14:25:40 +00:00
parent 8bb6eda9b2
commit 1962fa8781
7 changed files with 124 additions and 25 deletions

View File

@ -1,6 +1,6 @@
.\" -*- nroff -*-
.\"
.\" $NetBSD: bpf.4,v 1.51 2012/10/28 20:19:30 alnsn Exp $
.\" $NetBSD: bpf.4,v 1.52 2013/08/29 14:25:41 rmind Exp $
.\"
.\" Copyright (c) 1990, 1991, 1992, 1993, 1994
.\" The Regents of the University of California. All rights reserved.
@ -630,6 +630,16 @@ that copy the index register to the accumulator or vice versa.
.It Sy BPF_MISC+BPF_TAX Ta X \*[Lt]- A
.It Sy BPF_MISC+BPF_TXA Ta A \*[Lt]- X
.El
.Pp
Also, two instructions to call a "coprocessor" if initialized by the kernel
component. There is no coprocessor by default.
.Bl -column "BPF_MISC+BPF_COP" "A \*[Lt]- funcs[X](...)" -offset indent
.It Sy BPF_MISC+BPF_COP Ta A \*[Lt]- funcs[k](..)
.It Sy BPF_MISC+BPF_COPX Ta A \*[Lt]- funcs[X](..)
.El
.Pp
If the coprocessor is not set or the function index is out of range, these
instructions will abort the program and return zero.
.El
.Pp
The BPF interface provides the following macros to facilitate

View File

@ -1,4 +1,4 @@
/* $NetBSD: fil.c,v 1.8 2013/01/09 13:23:20 christos Exp $ */
/* $NetBSD: fil.c,v 1.9 2013/08/29 14:25:40 rmind Exp $ */
/*
* Copyright (C) 2012 by Darren Reed.
@ -138,7 +138,7 @@ extern struct timeout ipf_slowtimer_ch;
#if !defined(lint)
#if defined(__NetBSD__)
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: fil.c,v 1.8 2013/01/09 13:23:20 christos Exp $");
__KERNEL_RCSID(0, "$NetBSD: fil.c,v 1.9 2013/08/29 14:25:40 rmind Exp $");
#else
static const char sccsid[] = "@(#)fil.c 1.36 6/5/96 (C) 1993-2000 Darren Reed";
static const char rcsid[] = "@(#)Id: fil.c,v 1.1.1.2 2012/07/22 13:45:07 darrenr Exp $";
@ -2405,8 +2405,13 @@ ipf_scanlist(fr_info_t *fin, u_32_t pass)
continue;
mc = (u_char *)fin->fin_m;
wlen = fin->fin_dlen + fin->fin_hlen;
#if defined(__NetBSD__)
if (!bpf_filter(bpf_def_ctx, fr->fr_data, mc, wlen, 0))
continue;
#else
if (!bpf_filter(fr->fr_data, mc, wlen, 0))
continue;
#endif
break;
}
#endif

View File

@ -1,4 +1,4 @@
/* $NetBSD: bpf.c,v 1.173 2012/10/27 22:36:14 alnsn Exp $ */
/* $NetBSD: bpf.c,v 1.174 2013/08/29 14:25:41 rmind Exp $ */
/*
* Copyright (c) 1990, 1991, 1993
@ -39,7 +39,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: bpf.c,v 1.173 2012/10/27 22:36:14 alnsn Exp $");
__KERNEL_RCSID(0, "$NetBSD: bpf.c,v 1.174 2013/08/29 14:25:41 rmind Exp $");
#if defined(_KERNEL_OPT)
#include "opt_bpf.h"
@ -1382,7 +1382,8 @@ bpf_deliver(struct bpf_if *bp, void *(*cpfn)(void *, const void *, size_t),
if (d->bd_jitcode != NULL)
slen = d->bd_jitcode(pkt, pktlen, buflen);
else
slen = bpf_filter(d->bd_filter, pkt, pktlen, buflen);
slen = bpf_filter(bpf_def_ctx, d->bd_filter,
pkt, pktlen, buflen);
if (!slen) {
continue;

View File

@ -1,4 +1,4 @@
/* $NetBSD: bpf.h,v 1.59 2012/03/15 00:57:56 christos Exp $ */
/* $NetBSD: bpf.h,v 1.60 2013/08/29 14:25:41 rmind Exp $ */
/*
* Copyright (c) 1990, 1991, 1993
@ -254,6 +254,8 @@ struct bpf_hdr32 {
/* misc */
#define BPF_MISCOP(code) ((code) & 0xf8)
#define BPF_TAX 0x00
#define BPF_COP 0x20
#define BPF_COPX 0x40
#define BPF_TXA 0x80
/*
@ -378,10 +380,25 @@ void bpf_ops_handover_exit(void);
void bpfilterattach(int);
#endif
struct bpf_ctx;
typedef struct bpf_ctx bpf_ctx_t;
typedef uint32_t (*bpf_copfunc_t)(const struct mbuf *, uint32_t, uint32_t *);
extern bpf_ctx_t *bpf_def_ctx;
int bpf_validate(const struct bpf_insn *, int);
u_int bpf_filter(const struct bpf_insn *, const u_char *, u_int, u_int);
bpf_ctx_t *bpf_create(void);
void bpf_destroy(bpf_ctx_t *);
int bpf_set_cop(bpf_ctx_t *, const bpf_copfunc_t *, size_t);
u_int bpf_filter(bpf_ctx_t *, const struct bpf_insn *,
const u_char *, u_int, u_int);
int bpf_validate(const struct bpf_insn *, int);
#else
int bpf_validate(const struct bpf_insn *, int);
u_int bpf_filter(const struct bpf_insn *, const u_char *, u_int, u_int);
#endif
__END_DECLS

View File

@ -1,4 +1,4 @@
/* $NetBSD: bpf_filter.c,v 1.55 2012/10/27 22:36:14 alnsn Exp $ */
/* $NetBSD: bpf_filter.c,v 1.56 2013/08/29 14:25:41 rmind Exp $ */
/*-
* Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997
@ -37,7 +37,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: bpf_filter.c,v 1.55 2012/10/27 22:36:14 alnsn Exp $");
__KERNEL_RCSID(0, "$NetBSD: bpf_filter.c,v 1.56 2013/08/29 14:25:41 rmind Exp $");
#if 0
#if !(defined(lint) || defined(KERNEL))
@ -51,6 +51,41 @@ static const char rcsid[] =
#include <sys/kmem.h>
#include <sys/endian.h>
#include <net/bpf.h>
#ifdef _KERNEL
struct bpf_ctx {
const bpf_copfunc_t * copfuncs;
size_t nfuncs;
};
/* Default BPF context (zeroed). */
static bpf_ctx_t bpf_def_ctx1;
bpf_ctx_t * bpf_def_ctx = &bpf_def_ctx1;
bpf_ctx_t *
bpf_create(void)
{
return kmem_zalloc(sizeof(bpf_ctx_t), KM_SLEEP);
}
void
bpf_destroy(bpf_ctx_t *bc)
{
kmem_free(bc, sizeof(bpf_ctx_t));
}
int
bpf_set_cop(bpf_ctx_t *bc, const bpf_copfunc_t *funcs, size_t n)
{
bc->copfuncs = funcs;
bc->nfuncs = n;
return 0;
}
#endif
#define EXTRACT_SHORT(p) be16dec(p)
#define EXTRACT_LONG(p) be32dec(p)
@ -143,13 +178,23 @@ m_xbyte(const struct mbuf *m, uint32_t k, int *err)
* wirelen is the length of the original packet
* buflen is the amount of data present
*/
#ifdef _KERNEL
u_int
bpf_filter(bpf_ctx_t *bc, const struct bpf_insn *pc, const u_char *p,
u_int wirelen, u_int buflen)
#else
u_int
bpf_filter(const struct bpf_insn *pc, const u_char *p, u_int wirelen,
u_int buflen)
#endif
{
uint32_t A, X, k;
uint32_t mem[BPF_MEMWORDS];
#ifdef _KERNEL
KASSERT(bc != NULL);
#endif
if (pc == 0) {
/*
* No filter means accept all.
@ -465,6 +510,26 @@ bpf_filter(const struct bpf_insn *pc, const u_char *p, u_int wirelen,
case BPF_MISC|BPF_TXA:
A = X;
continue;
case BPF_MISC|BPF_COP:
#ifdef _KERNEL
if (pc->k < bc->nfuncs) {
const bpf_copfunc_t fn = bc->copfuncs[pc->k];
A = fn((const struct mbuf *)p, A, mem);
continue;
}
#endif
return 0;
case BPF_MISC|BPF_COPX:
#ifdef _KERNEL
if (X < bc->nfuncs) {
const bpf_copfunc_t fn = bc->copfuncs[X];
A = fn((const struct mbuf *)p, A, mem);
continue;
}
#endif
return 0;
}
}
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: if_ppp.c,v 1.138 2012/11/25 09:06:43 mbalmer Exp $ */
/* $NetBSD: if_ppp.c,v 1.139 2013/08/29 14:25:41 rmind Exp $ */
/* Id: if_ppp.c,v 1.6 1997/03/04 03:33:00 paulus Exp */
/*
@ -102,7 +102,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: if_ppp.c,v 1.138 2012/11/25 09:06:43 mbalmer Exp $");
__KERNEL_RCSID(0, "$NetBSD: if_ppp.c,v 1.139 2013/08/29 14:25:41 rmind Exp $");
#include "ppp.h"
@ -946,8 +946,8 @@ pppoutput(struct ifnet *ifp, struct mbuf *m0, const struct sockaddr *dst,
* but only if it is a data packet.
*/
if (sc->sc_pass_filt_out.bf_insns != 0
&& bpf_filter(sc->sc_pass_filt_out.bf_insns, (u_char *) m0,
len, 0) == 0) {
&& bpf_filter(bpf_def_ctx, sc->sc_pass_filt_out.bf_insns,
(u_char *)m0, len, 0) == 0) {
error = 0; /* drop this packet */
goto bad;
}
@ -956,8 +956,8 @@ pppoutput(struct ifnet *ifp, struct mbuf *m0, const struct sockaddr *dst,
* Update the time we sent the most recent packet.
*/
if (sc->sc_active_filt_out.bf_insns == 0
|| bpf_filter(sc->sc_active_filt_out.bf_insns, (u_char *) m0,
len, 0))
|| bpf_filter(bpf_def_ctx, sc->sc_active_filt_out.bf_insns,
(u_char *)m0, len, 0))
sc->sc_last_sent = time_second;
#else
/*
@ -1584,15 +1584,15 @@ ppp_inproc(struct ppp_softc *sc, struct mbuf *m)
* if it counts as link activity.
*/
if (sc->sc_pass_filt_in.bf_insns != 0
&& bpf_filter(sc->sc_pass_filt_in.bf_insns, (u_char *) m,
ilen, 0) == 0) {
&& bpf_filter(bpf_def_ctx, sc->sc_pass_filt_in.bf_insns,
(u_char *)m, ilen, 0) == 0) {
/* drop this packet */
m_freem(m);
return;
}
if (sc->sc_active_filt_in.bf_insns == 0
|| bpf_filter(sc->sc_active_filt_in.bf_insns, (u_char *) m,
ilen, 0))
|| bpf_filter(bpf_def_ctx, sc->sc_active_filt_in.bf_insns,
(u_char *)m, ilen, 0))
sc->sc_last_recv = time_second;
#else
/*

View File

@ -1,4 +1,4 @@
/* $NetBSD: npf_ruleset.c,v 1.20 2013/03/18 02:24:45 rmind Exp $ */
/* $NetBSD: npf_ruleset.c,v 1.21 2013/08/29 14:25:41 rmind Exp $ */
/*-
* Copyright (c) 2009-2013 The NetBSD Foundation, Inc.
@ -34,7 +34,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: npf_ruleset.c,v 1.20 2013/03/18 02:24:45 rmind Exp $");
__KERNEL_RCSID(0, "$NetBSD: npf_ruleset.c,v 1.21 2013/08/29 14:25:41 rmind Exp $");
#include <sys/param.h>
#include <sys/types.h>
@ -681,7 +681,8 @@ npf_rule_inspect(npf_cache_t *npc, nbuf_t *nbuf, const npf_rule_t *rl,
case NPF_CODE_BPF: {
struct mbuf *m = nbuf_head_mbuf(nbuf);
size_t pktlen = m_length(m);
return bpf_filter(code, (unsigned char *)m, pktlen, 0) != 0;
return bpf_filter(bpf_def_ctx, code, (unsigned char *)m,
pktlen, 0) != 0;
}
default:
KASSERT(false);