xref: /netbsd-src/sys/net/npf/npf_bpf.c (revision 796c32c94f6e154afc9de0f63da35c91bb739b45)
1 /*	$NetBSD: npf_bpf.c,v 1.12 2016/12/26 23:05:06 christos Exp $	*/
2 
3 /*-
4  * Copyright (c) 2009-2013 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This material is based upon work partially supported by The
8  * NetBSD Foundation under a contract with Mindaugas Rasiukevicius.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 /*
33  * NPF byte-code processing.
34  */
35 
36 #ifdef _KERNEL
37 #include <sys/cdefs.h>
38 __KERNEL_RCSID(0, "$NetBSD: npf_bpf.c,v 1.12 2016/12/26 23:05:06 christos Exp $");
39 
40 #include <sys/types.h>
41 #include <sys/param.h>
42 
43 #include <sys/bitops.h>
44 #include <sys/mbuf.h>
45 #include <net/bpf.h>
46 #endif
47 
48 #define NPF_BPFCOP
49 #include "npf_impl.h"
50 
51 #if defined(_NPF_STANDALONE)
52 #define	m_length(m)		(nbuf)->nb_mops->getchainlen(m)
53 #endif
54 
55 /*
56  * BPF context and the coprocessor.
57  */
58 
59 static bpf_ctx_t *npf_bpfctx __read_mostly;
60 
61 static uint32_t	npf_cop_l3(const bpf_ctx_t *, bpf_args_t *, uint32_t);
62 static uint32_t	npf_cop_table(const bpf_ctx_t *, bpf_args_t *, uint32_t);
63 
64 static const bpf_copfunc_t npf_bpfcop[] = {
65 	[NPF_COP_L3]	= npf_cop_l3,
66 	[NPF_COP_TABLE]	= npf_cop_table,
67 };
68 
69 #define	BPF_MW_ALLMASK \
70     ((1U << BPF_MW_IPVER) | (1U << BPF_MW_L4OFF) | (1U << BPF_MW_L4PROTO))
71 
72 void
73 npf_bpf_sysinit(void)
74 {
75 	npf_bpfctx = bpf_create();
76 	bpf_set_cop(npf_bpfctx, npf_bpfcop, __arraycount(npf_bpfcop));
77 	bpf_set_extmem(npf_bpfctx, NPF_BPF_NWORDS, BPF_MW_ALLMASK);
78 }
79 
80 void
81 npf_bpf_sysfini(void)
82 {
83 	bpf_destroy(npf_bpfctx);
84 }
85 
86 void
87 npf_bpf_prepare(npf_cache_t *npc, bpf_args_t *args, uint32_t *M)
88 {
89 	nbuf_t *nbuf = npc->npc_nbuf;
90 	const struct mbuf *mbuf = nbuf_head_mbuf(nbuf);
91 	const size_t pktlen = m_length(mbuf);
92 
93 	/* Prepare the arguments for the BPF programs. */
94 #ifdef _NPF_STANDALONE
95 	args->pkt = (const uint8_t *)nbuf_dataptr(nbuf);
96 	args->wirelen = args->buflen = pktlen;
97 #else
98 	args->pkt = (const uint8_t *)mbuf;
99 	args->wirelen = pktlen;
100 	args->buflen = 0;
101 #endif
102 	args->mem = M;
103 	args->arg = npc;
104 
105 	/*
106 	 * Convert address length to IP version.  Just mask out
107 	 * number 4 or set 6 if higher bits set, such that:
108 	 *
109 	 *	0	=>	0
110 	 *	4	=>	4 (IPVERSION)
111 	 *	16	=>	6 (IPV6_VERSION >> 4)
112 	 */
113 	const u_int alen = npc->npc_alen;
114 	const uint32_t ver = (alen & 4) | ((alen >> 4) * 6);
115 
116 	/*
117 	 * Output words in the memory store:
118 	 *	BPF_MW_IPVER	IP version (4 or 6).
119 	 *	BPF_MW_L4OFF	L4 header offset.
120 	 *	BPF_MW_L4PROTO	L4 protocol.
121 	 */
122 	M[BPF_MW_IPVER] = ver;
123 	M[BPF_MW_L4OFF] = npc->npc_hlen;
124 	M[BPF_MW_L4PROTO] = npc->npc_proto;
125 }
126 
127 int
128 npf_bpf_filter(bpf_args_t *args, const void *code, bpfjit_func_t jcode)
129 {
130 	/* Execute JIT-compiled code. */
131 	if (__predict_true(jcode)) {
132 		return jcode(npf_bpfctx, args);
133 	}
134 
135 	/* Execute BPF byte-code. */
136 	return bpf_filter_ext(npf_bpfctx, code, args);
137 }
138 
139 void *
140 npf_bpf_compile(void *code, size_t size)
141 {
142 	return bpf_jit_generate(npf_bpfctx, code, size);
143 }
144 
145 bool
146 npf_bpf_validate(const void *code, size_t len)
147 {
148 	const size_t icount = len / sizeof(struct bpf_insn);
149 	return bpf_validate_ext(npf_bpfctx, code, icount) != 0;
150 }
151 
152 /*
153  * NPF_COP_L3: fetches layer 3 information.
154  */
155 static uint32_t
156 npf_cop_l3(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A)
157 {
158 	const npf_cache_t * const npc = (const npf_cache_t *)args->arg;
159 	const uint32_t ver = (npc->npc_alen & 4) | ((npc->npc_alen >> 4) * 6);
160 	uint32_t * const M = args->mem;
161 
162 	M[BPF_MW_IPVER] = ver;
163 	M[BPF_MW_L4OFF] = npc->npc_hlen;
164 	M[BPF_MW_L4PROTO] = npc->npc_proto;
165 	return ver; /* A <- IP version */
166 }
167 
168 #define	SRC_FLAG_BIT	(1U << 31)
169 
170 /*
171  * NPF_COP_TABLE: perform NPF table lookup.
172  *
173  *	A <- non-zero (true) if found and zero (false) otherwise
174  */
175 static uint32_t
176 npf_cop_table(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A)
177 {
178 	const npf_cache_t * const npc = (const npf_cache_t *)args->arg;
179 	npf_tableset_t *tblset = npf_config_tableset(npc->npc_ctx);
180 	const uint32_t tid = A & (SRC_FLAG_BIT - 1);
181 	const npf_addr_t *addr;
182 	npf_table_t *t;
183 
184 	KASSERT(npf_iscached(npc, NPC_IP46));
185 
186 	if ((t = npf_tableset_getbyid(tblset, tid)) == NULL) {
187 		return 0;
188 	}
189 	addr = npc->npc_ips[(A & SRC_FLAG_BIT) ? NPF_SRC : NPF_DST];
190 	return npf_table_lookup(t, npc->npc_alen, addr) == 0;
191 }
192