xref: /netbsd-src/sys/net/npf/npf_bpf.c (revision 39013e66c1ab98cbf1ceb3a94595880d6763083b)
14e592132Srmind /*-
24e592132Srmind  * Copyright (c) 2009-2013 The NetBSD Foundation, Inc.
34e592132Srmind  * All rights reserved.
44e592132Srmind  *
54e592132Srmind  * This material is based upon work partially supported by The
64e592132Srmind  * NetBSD Foundation under a contract with Mindaugas Rasiukevicius.
74e592132Srmind  *
84e592132Srmind  * Redistribution and use in source and binary forms, with or without
94e592132Srmind  * modification, are permitted provided that the following conditions
104e592132Srmind  * are met:
114e592132Srmind  * 1. Redistributions of source code must retain the above copyright
124e592132Srmind  *    notice, this list of conditions and the following disclaimer.
134e592132Srmind  * 2. Redistributions in binary form must reproduce the above copyright
144e592132Srmind  *    notice, this list of conditions and the following disclaimer in the
154e592132Srmind  *    documentation and/or other materials provided with the distribution.
164e592132Srmind  *
174e592132Srmind  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
184e592132Srmind  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
194e592132Srmind  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
204e592132Srmind  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
214e592132Srmind  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
224e592132Srmind  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
234e592132Srmind  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
244e592132Srmind  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
254e592132Srmind  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
264e592132Srmind  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
274e592132Srmind  * POSSIBILITY OF SUCH DAMAGE.
284e592132Srmind  */
294e592132Srmind 
304e592132Srmind /*
314e592132Srmind  * NPF byte-code processing.
324e592132Srmind  */
334e592132Srmind 
34f75d79ebSchristos #ifdef _KERNEL
354e592132Srmind #include <sys/cdefs.h>
36*39013e66Srmind __KERNEL_RCSID(0, "$NetBSD: npf_bpf.c,v 1.14 2018/09/29 14:41:36 rmind Exp $");
374e592132Srmind 
384e592132Srmind #include <sys/types.h>
394e592132Srmind #include <sys/param.h>
404e592132Srmind 
41263d30c4Srmind #include <sys/bitops.h>
424e592132Srmind #include <sys/mbuf.h>
43c782c888Srmind #include <net/bpf.h>
44f75d79ebSchristos #endif
454e592132Srmind 
464e592132Srmind #define NPF_BPFCOP
474e592132Srmind #include "npf_impl.h"
484e592132Srmind 
49f75d79ebSchristos #if defined(_NPF_STANDALONE)
50f75d79ebSchristos #define	m_length(m)		(nbuf)->nb_mops->getchainlen(m)
51f75d79ebSchristos #endif
52f75d79ebSchristos 
534e592132Srmind /*
544e592132Srmind  * BPF context and the coprocessor.
554e592132Srmind  */
564e592132Srmind 
574e592132Srmind static bpf_ctx_t *npf_bpfctx __read_mostly;
584e592132Srmind 
59f9dc8d88Salnsn static uint32_t	npf_cop_l3(const bpf_ctx_t *, bpf_args_t *, uint32_t);
60f9dc8d88Salnsn static uint32_t	npf_cop_table(const bpf_ctx_t *, bpf_args_t *, uint32_t);
614e592132Srmind 
624e592132Srmind static const bpf_copfunc_t npf_bpfcop[] = {
634e592132Srmind 	[NPF_COP_L3]	= npf_cop_l3,
644e592132Srmind 	[NPF_COP_TABLE]	= npf_cop_table,
654e592132Srmind };
664e592132Srmind 
67263d30c4Srmind #define	BPF_MW_ALLMASK \
68263d30c4Srmind     ((1U << BPF_MW_IPVER) | (1U << BPF_MW_L4OFF) | (1U << BPF_MW_L4PROTO))
69263d30c4Srmind 
704e592132Srmind void
npf_bpf_sysinit(void)714e592132Srmind npf_bpf_sysinit(void)
724e592132Srmind {
734e592132Srmind 	npf_bpfctx = bpf_create();
744e592132Srmind 	bpf_set_cop(npf_bpfctx, npf_bpfcop, __arraycount(npf_bpfcop));
75263d30c4Srmind 	bpf_set_extmem(npf_bpfctx, NPF_BPF_NWORDS, BPF_MW_ALLMASK);
764e592132Srmind }
774e592132Srmind 
784e592132Srmind void
npf_bpf_sysfini(void)794e592132Srmind npf_bpf_sysfini(void)
804e592132Srmind {
814e592132Srmind 	bpf_destroy(npf_bpfctx);
824e592132Srmind }
834e592132Srmind 
84263d30c4Srmind void
npf_bpf_prepare(npf_cache_t * npc,bpf_args_t * args,uint32_t * M)85a7d2a608Srmind npf_bpf_prepare(npf_cache_t *npc, bpf_args_t *args, uint32_t *M)
86263d30c4Srmind {
87f75d79ebSchristos 	nbuf_t *nbuf = npc->npc_nbuf;
88f75d79ebSchristos 	const struct mbuf *mbuf = nbuf_head_mbuf(nbuf);
89263d30c4Srmind 	const size_t pktlen = m_length(mbuf);
90263d30c4Srmind 
91263d30c4Srmind 	/* Prepare the arguments for the BPF programs. */
92f75d79ebSchristos #ifdef _NPF_STANDALONE
93f75d79ebSchristos 	args->pkt = (const uint8_t *)nbuf_dataptr(nbuf);
94f75d79ebSchristos 	args->wirelen = args->buflen = pktlen;
95f75d79ebSchristos #else
96263d30c4Srmind 	args->pkt = (const uint8_t *)mbuf;
97263d30c4Srmind 	args->wirelen = pktlen;
98263d30c4Srmind 	args->buflen = 0;
99f75d79ebSchristos #endif
1009c7a886eSrmind 	args->mem = M;
101263d30c4Srmind 	args->arg = npc;
1029c7a886eSrmind 
1039c7a886eSrmind 	/*
1049c7a886eSrmind 	 * Convert address length to IP version.  Just mask out
1059c7a886eSrmind 	 * number 4 or set 6 if higher bits set, such that:
1069c7a886eSrmind 	 *
1079c7a886eSrmind 	 *	0	=>	0
1089c7a886eSrmind 	 *	4	=>	4 (IPVERSION)
1099c7a886eSrmind 	 *	16	=>	6 (IPV6_VERSION >> 4)
1109c7a886eSrmind 	 */
1119c7a886eSrmind 	const u_int alen = npc->npc_alen;
1129c7a886eSrmind 	const uint32_t ver = (alen & 4) | ((alen >> 4) * 6);
1139c7a886eSrmind 
1149c7a886eSrmind 	/*
1159c7a886eSrmind 	 * Output words in the memory store:
1169c7a886eSrmind 	 *	BPF_MW_IPVER	IP version (4 or 6).
1179c7a886eSrmind 	 *	BPF_MW_L4OFF	L4 header offset.
1189c7a886eSrmind 	 *	BPF_MW_L4PROTO	L4 protocol.
1199c7a886eSrmind 	 */
1209c7a886eSrmind 	M[BPF_MW_IPVER] = ver;
1219c7a886eSrmind 	M[BPF_MW_L4OFF] = npc->npc_hlen;
1229c7a886eSrmind 	M[BPF_MW_L4PROTO] = npc->npc_proto;
123263d30c4Srmind }
124263d30c4Srmind 
1254e592132Srmind int
npf_bpf_filter(bpf_args_t * args,const void * code,bpfjit_func_t jcode)126c4d05d45Srmind npf_bpf_filter(bpf_args_t *args, const void *code, bpfjit_func_t jcode)
1274e592132Srmind {
128c4d05d45Srmind 	/* Execute JIT-compiled code. */
1294e592132Srmind 	if (__predict_true(jcode)) {
130c4d05d45Srmind 		return jcode(npf_bpfctx, args);
1314e592132Srmind 	}
1329c7a886eSrmind 
1334e592132Srmind 	/* Execute BPF byte-code. */
134c4d05d45Srmind 	return bpf_filter_ext(npf_bpfctx, code, args);
1354e592132Srmind }
1364e592132Srmind 
137c782c888Srmind void *
npf_bpf_compile(void * code,size_t size)138c782c888Srmind npf_bpf_compile(void *code, size_t size)
139c782c888Srmind {
140c782c888Srmind 	return bpf_jit_generate(npf_bpfctx, code, size);
141c782c888Srmind }
142c782c888Srmind 
1434e592132Srmind bool
npf_bpf_validate(const void * code,size_t len)1444e592132Srmind npf_bpf_validate(const void *code, size_t len)
1454e592132Srmind {
1464e592132Srmind 	const size_t icount = len / sizeof(struct bpf_insn);
1474e592132Srmind 	return bpf_validate_ext(npf_bpfctx, code, icount) != 0;
1484e592132Srmind }
1494e592132Srmind 
1504e592132Srmind /*
1514e592132Srmind  * NPF_COP_L3: fetches layer 3 information.
1524e592132Srmind  */
1534e592132Srmind static uint32_t
npf_cop_l3(const bpf_ctx_t * bc,bpf_args_t * args,uint32_t A)154f9dc8d88Salnsn npf_cop_l3(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A)
1554e592132Srmind {
156d0748eb9Srmind 	const npf_cache_t * const npc = (const npf_cache_t *)args->arg;
1579c7a886eSrmind 	const uint32_t ver = (npc->npc_alen & 4) | ((npc->npc_alen >> 4) * 6);
158d0748eb9Srmind 	uint32_t * const M = args->mem;
1594e592132Srmind 
1604e592132Srmind 	M[BPF_MW_IPVER] = ver;
1614e592132Srmind 	M[BPF_MW_L4OFF] = npc->npc_hlen;
1624e592132Srmind 	M[BPF_MW_L4PROTO] = npc->npc_proto;
1639c7a886eSrmind 	return ver; /* A <- IP version */
1644e592132Srmind }
1654e592132Srmind 
1664e592132Srmind #define	SRC_FLAG_BIT	(1U << 31)
1674e592132Srmind 
1684e592132Srmind /*
1694e592132Srmind  * NPF_COP_TABLE: perform NPF table lookup.
1704e592132Srmind  *
1714e592132Srmind  *	A <- non-zero (true) if found and zero (false) otherwise
1724e592132Srmind  */
1734e592132Srmind static uint32_t
npf_cop_table(const bpf_ctx_t * bc,bpf_args_t * args,uint32_t A)174f9dc8d88Salnsn npf_cop_table(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A)
1754e592132Srmind {
176d0748eb9Srmind 	const npf_cache_t * const npc = (const npf_cache_t *)args->arg;
177f75d79ebSchristos 	npf_tableset_t *tblset = npf_config_tableset(npc->npc_ctx);
1784e592132Srmind 	const uint32_t tid = A & (SRC_FLAG_BIT - 1);
1794e592132Srmind 	const npf_addr_t *addr;
1801e7342c1Srmind 	npf_table_t *t;
1814e592132Srmind 
1820def1972Srmind 	if (!npf_iscached(npc, NPC_IP46)) {
1830def1972Srmind 		return 0;
1840def1972Srmind 	}
1850def1972Srmind 	t = npf_tableset_getbyid(tblset, tid);
1860def1972Srmind 	if (__predict_false(!t)) {
1871e7342c1Srmind 		return 0;
1881e7342c1Srmind 	}
1898a8347bdSrmind 	addr = npc->npc_ips[(A & SRC_FLAG_BIT) ? NPF_SRC : NPF_DST];
1901e7342c1Srmind 	return npf_table_lookup(t, npc->npc_alen, addr) == 0;
1914e592132Srmind }
192