xref: /netbsd/sys/net/npf/npf_bpf.c (revision 94550a6d)
111243735Srmind /*-
211243735Srmind  * Copyright (c) 2009-2013 The NetBSD Foundation, Inc.
311243735Srmind  * All rights reserved.
411243735Srmind  *
511243735Srmind  * This material is based upon work partially supported by The
611243735Srmind  * NetBSD Foundation under a contract with Mindaugas Rasiukevicius.
711243735Srmind  *
811243735Srmind  * Redistribution and use in source and binary forms, with or without
911243735Srmind  * modification, are permitted provided that the following conditions
1011243735Srmind  * are met:
1111243735Srmind  * 1. Redistributions of source code must retain the above copyright
1211243735Srmind  *    notice, this list of conditions and the following disclaimer.
1311243735Srmind  * 2. Redistributions in binary form must reproduce the above copyright
1411243735Srmind  *    notice, this list of conditions and the following disclaimer in the
1511243735Srmind  *    documentation and/or other materials provided with the distribution.
1611243735Srmind  *
1711243735Srmind  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
1811243735Srmind  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
1911243735Srmind  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2011243735Srmind  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
2111243735Srmind  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2211243735Srmind  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2311243735Srmind  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2411243735Srmind  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2511243735Srmind  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2611243735Srmind  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2711243735Srmind  * POSSIBILITY OF SUCH DAMAGE.
2811243735Srmind  */
2911243735Srmind 
3011243735Srmind /*
3111243735Srmind  * NPF byte-code processing.
3211243735Srmind  */
3311243735Srmind 
340473fe8bSchristos #ifdef _KERNEL
3511243735Srmind #include <sys/cdefs.h>
36*94550a6dSrmind __KERNEL_RCSID(0, "$NetBSD: npf_bpf.c,v 1.14 2018/09/29 14:41:36 rmind Exp $");
3711243735Srmind 
3811243735Srmind #include <sys/types.h>
3911243735Srmind #include <sys/param.h>
4011243735Srmind 
415cd3adceSrmind #include <sys/bitops.h>
4211243735Srmind #include <sys/mbuf.h>
43c9e2fc6cSrmind #include <net/bpf.h>
440473fe8bSchristos #endif
4511243735Srmind 
4611243735Srmind #define NPF_BPFCOP
4711243735Srmind #include "npf_impl.h"
4811243735Srmind 
490473fe8bSchristos #if defined(_NPF_STANDALONE)
500473fe8bSchristos #define	m_length(m)		(nbuf)->nb_mops->getchainlen(m)
510473fe8bSchristos #endif
520473fe8bSchristos 
5311243735Srmind /*
5411243735Srmind  * BPF context and the coprocessor.
5511243735Srmind  */
5611243735Srmind 
5711243735Srmind static bpf_ctx_t *npf_bpfctx __read_mostly;
5811243735Srmind 
59066eedd6Salnsn static uint32_t	npf_cop_l3(const bpf_ctx_t *, bpf_args_t *, uint32_t);
60066eedd6Salnsn static uint32_t	npf_cop_table(const bpf_ctx_t *, bpf_args_t *, uint32_t);
6111243735Srmind 
6211243735Srmind static const bpf_copfunc_t npf_bpfcop[] = {
6311243735Srmind 	[NPF_COP_L3]	= npf_cop_l3,
6411243735Srmind 	[NPF_COP_TABLE]	= npf_cop_table,
6511243735Srmind };
6611243735Srmind 
675cd3adceSrmind #define	BPF_MW_ALLMASK \
685cd3adceSrmind     ((1U << BPF_MW_IPVER) | (1U << BPF_MW_L4OFF) | (1U << BPF_MW_L4PROTO))
695cd3adceSrmind 
7011243735Srmind void
npf_bpf_sysinit(void)7111243735Srmind npf_bpf_sysinit(void)
7211243735Srmind {
7311243735Srmind 	npf_bpfctx = bpf_create();
7411243735Srmind 	bpf_set_cop(npf_bpfctx, npf_bpfcop, __arraycount(npf_bpfcop));
755cd3adceSrmind 	bpf_set_extmem(npf_bpfctx, NPF_BPF_NWORDS, BPF_MW_ALLMASK);
7611243735Srmind }
7711243735Srmind 
7811243735Srmind void
npf_bpf_sysfini(void)7911243735Srmind npf_bpf_sysfini(void)
8011243735Srmind {
8111243735Srmind 	bpf_destroy(npf_bpfctx);
8211243735Srmind }
8311243735Srmind 
845cd3adceSrmind void
npf_bpf_prepare(npf_cache_t * npc,bpf_args_t * args,uint32_t * M)85d5cb4211Srmind npf_bpf_prepare(npf_cache_t *npc, bpf_args_t *args, uint32_t *M)
865cd3adceSrmind {
870473fe8bSchristos 	nbuf_t *nbuf = npc->npc_nbuf;
880473fe8bSchristos 	const struct mbuf *mbuf = nbuf_head_mbuf(nbuf);
895cd3adceSrmind 	const size_t pktlen = m_length(mbuf);
905cd3adceSrmind 
915cd3adceSrmind 	/* Prepare the arguments for the BPF programs. */
920473fe8bSchristos #ifdef _NPF_STANDALONE
930473fe8bSchristos 	args->pkt = (const uint8_t *)nbuf_dataptr(nbuf);
940473fe8bSchristos 	args->wirelen = args->buflen = pktlen;
950473fe8bSchristos #else
965cd3adceSrmind 	args->pkt = (const uint8_t *)mbuf;
975cd3adceSrmind 	args->wirelen = pktlen;
985cd3adceSrmind 	args->buflen = 0;
990473fe8bSchristos #endif
100471a4a00Srmind 	args->mem = M;
1015cd3adceSrmind 	args->arg = npc;
102471a4a00Srmind 
103471a4a00Srmind 	/*
104471a4a00Srmind 	 * Convert address length to IP version.  Just mask out
105471a4a00Srmind 	 * number 4 or set 6 if higher bits set, such that:
106471a4a00Srmind 	 *
107471a4a00Srmind 	 *	0	=>	0
108471a4a00Srmind 	 *	4	=>	4 (IPVERSION)
109471a4a00Srmind 	 *	16	=>	6 (IPV6_VERSION >> 4)
110471a4a00Srmind 	 */
111471a4a00Srmind 	const u_int alen = npc->npc_alen;
112471a4a00Srmind 	const uint32_t ver = (alen & 4) | ((alen >> 4) * 6);
113471a4a00Srmind 
114471a4a00Srmind 	/*
115471a4a00Srmind 	 * Output words in the memory store:
116471a4a00Srmind 	 *	BPF_MW_IPVER	IP version (4 or 6).
117471a4a00Srmind 	 *	BPF_MW_L4OFF	L4 header offset.
118471a4a00Srmind 	 *	BPF_MW_L4PROTO	L4 protocol.
119471a4a00Srmind 	 */
120471a4a00Srmind 	M[BPF_MW_IPVER] = ver;
121471a4a00Srmind 	M[BPF_MW_L4OFF] = npc->npc_hlen;
122471a4a00Srmind 	M[BPF_MW_L4PROTO] = npc->npc_proto;
1235cd3adceSrmind }
1245cd3adceSrmind 
12511243735Srmind int
npf_bpf_filter(bpf_args_t * args,const void * code,bpfjit_func_t jcode)1264659660dSrmind npf_bpf_filter(bpf_args_t *args, const void *code, bpfjit_func_t jcode)
12711243735Srmind {
1284659660dSrmind 	/* Execute JIT-compiled code. */
12911243735Srmind 	if (__predict_true(jcode)) {
1304659660dSrmind 		return jcode(npf_bpfctx, args);
13111243735Srmind 	}
132471a4a00Srmind 
13311243735Srmind 	/* Execute BPF byte-code. */
1344659660dSrmind 	return bpf_filter_ext(npf_bpfctx, code, args);
13511243735Srmind }
13611243735Srmind 
137c9e2fc6cSrmind void *
npf_bpf_compile(void * code,size_t size)138c9e2fc6cSrmind npf_bpf_compile(void *code, size_t size)
139c9e2fc6cSrmind {
140c9e2fc6cSrmind 	return bpf_jit_generate(npf_bpfctx, code, size);
141c9e2fc6cSrmind }
142c9e2fc6cSrmind 
14311243735Srmind bool
npf_bpf_validate(const void * code,size_t len)14411243735Srmind npf_bpf_validate(const void *code, size_t len)
14511243735Srmind {
14611243735Srmind 	const size_t icount = len / sizeof(struct bpf_insn);
14711243735Srmind 	return bpf_validate_ext(npf_bpfctx, code, icount) != 0;
14811243735Srmind }
14911243735Srmind 
15011243735Srmind /*
15111243735Srmind  * NPF_COP_L3: fetches layer 3 information.
15211243735Srmind  */
15311243735Srmind static uint32_t
npf_cop_l3(const bpf_ctx_t * bc,bpf_args_t * args,uint32_t A)154066eedd6Salnsn npf_cop_l3(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A)
15511243735Srmind {
156cd89282eSrmind 	const npf_cache_t * const npc = (const npf_cache_t *)args->arg;
157471a4a00Srmind 	const uint32_t ver = (npc->npc_alen & 4) | ((npc->npc_alen >> 4) * 6);
158cd89282eSrmind 	uint32_t * const M = args->mem;
15911243735Srmind 
16011243735Srmind 	M[BPF_MW_IPVER] = ver;
16111243735Srmind 	M[BPF_MW_L4OFF] = npc->npc_hlen;
16211243735Srmind 	M[BPF_MW_L4PROTO] = npc->npc_proto;
163471a4a00Srmind 	return ver; /* A <- IP version */
16411243735Srmind }
16511243735Srmind 
16611243735Srmind #define	SRC_FLAG_BIT	(1U << 31)
16711243735Srmind 
16811243735Srmind /*
16911243735Srmind  * NPF_COP_TABLE: perform NPF table lookup.
17011243735Srmind  *
17111243735Srmind  *	A <- non-zero (true) if found and zero (false) otherwise
17211243735Srmind  */
17311243735Srmind static uint32_t
npf_cop_table(const bpf_ctx_t * bc,bpf_args_t * args,uint32_t A)174066eedd6Salnsn npf_cop_table(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A)
17511243735Srmind {
176cd89282eSrmind 	const npf_cache_t * const npc = (const npf_cache_t *)args->arg;
1770473fe8bSchristos 	npf_tableset_t *tblset = npf_config_tableset(npc->npc_ctx);
17811243735Srmind 	const uint32_t tid = A & (SRC_FLAG_BIT - 1);
17911243735Srmind 	const npf_addr_t *addr;
180def81fffSrmind 	npf_table_t *t;
18111243735Srmind 
18211c8297cSrmind 	if (!npf_iscached(npc, NPC_IP46)) {
18311c8297cSrmind 		return 0;
18411c8297cSrmind 	}
18511c8297cSrmind 	t = npf_tableset_getbyid(tblset, tid);
18611c8297cSrmind 	if (__predict_false(!t)) {
187def81fffSrmind 		return 0;
188def81fffSrmind 	}
18924c949d4Srmind 	addr = npc->npc_ips[(A & SRC_FLAG_BIT) ? NPF_SRC : NPF_DST];
190def81fffSrmind 	return npf_table_lookup(t, npc->npc_alen, addr) == 0;
19111243735Srmind }
192