xref: /netbsd-src/sys/net/npf/npf_bpf.c (revision b7b7574d3bf8eeb51a1fa3977b59142ec6434a55)
1 /*	$NetBSD: npf_bpf.c,v 1.10 2014/06/30 00:01:23 rmind 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 #include <sys/cdefs.h>
37 __KERNEL_RCSID(0, "$NetBSD: npf_bpf.c,v 1.10 2014/06/30 00:01:23 rmind Exp $");
38 
39 #include <sys/types.h>
40 #include <sys/param.h>
41 
42 #include <sys/bitops.h>
43 #include <sys/mbuf.h>
44 #include <net/bpf.h>
45 
46 #define NPF_BPFCOP
47 #include "npf_impl.h"
48 
49 /*
50  * BPF context and the coprocessor.
51  */
52 
53 static bpf_ctx_t *npf_bpfctx __read_mostly;
54 
55 static uint32_t	npf_cop_l3(const bpf_ctx_t *, bpf_args_t *, uint32_t);
56 static uint32_t	npf_cop_table(const bpf_ctx_t *, bpf_args_t *, uint32_t);
57 
58 static const bpf_copfunc_t npf_bpfcop[] = {
59 	[NPF_COP_L3]	= npf_cop_l3,
60 	[NPF_COP_TABLE]	= npf_cop_table,
61 };
62 
63 #define	BPF_MW_ALLMASK \
64     ((1U << BPF_MW_IPVER) | (1U << BPF_MW_L4OFF) | (1U << BPF_MW_L4PROTO))
65 
66 void
67 npf_bpf_sysinit(void)
68 {
69 	npf_bpfctx = bpf_create();
70 	bpf_set_cop(npf_bpfctx, npf_bpfcop, __arraycount(npf_bpfcop));
71 	bpf_set_extmem(npf_bpfctx, NPF_BPF_NWORDS, BPF_MW_ALLMASK);
72 }
73 
74 void
75 npf_bpf_sysfini(void)
76 {
77 	bpf_destroy(npf_bpfctx);
78 }
79 
80 void
81 npf_bpf_prepare(npf_cache_t *npc, nbuf_t *nbuf, bpf_args_t *args, uint32_t *M)
82 {
83 	const struct mbuf *mbuf = nbuf_head_mbuf(nbuf);
84 	const size_t pktlen = m_length(mbuf);
85 
86 	/* Prepare the arguments for the BPF programs. */
87 	args->pkt = (const uint8_t *)mbuf;
88 	args->wirelen = pktlen;
89 	args->buflen = 0;
90 	args->mem = M;
91 	args->arg = npc;
92 
93 	/*
94 	 * Convert address length to IP version.  Just mask out
95 	 * number 4 or set 6 if higher bits set, such that:
96 	 *
97 	 *	0	=>	0
98 	 *	4	=>	4 (IPVERSION)
99 	 *	16	=>	6 (IPV6_VERSION >> 4)
100 	 */
101 	const u_int alen = npc->npc_alen;
102 	const uint32_t ver = (alen & 4) | ((alen >> 4) * 6);
103 
104 	/*
105 	 * Output words in the memory store:
106 	 *	BPF_MW_IPVER	IP version (4 or 6).
107 	 *	BPF_MW_L4OFF	L4 header offset.
108 	 *	BPF_MW_L4PROTO	L4 protocol.
109 	 */
110 	M[BPF_MW_IPVER] = ver;
111 	M[BPF_MW_L4OFF] = npc->npc_hlen;
112 	M[BPF_MW_L4PROTO] = npc->npc_proto;
113 }
114 
115 int
116 npf_bpf_filter(bpf_args_t *args, const void *code, bpfjit_func_t jcode)
117 {
118 	/* Execute JIT-compiled code. */
119 	if (__predict_true(jcode)) {
120 		return jcode(npf_bpfctx, args);
121 	}
122 
123 	/* Execute BPF byte-code. */
124 	return bpf_filter_ext(npf_bpfctx, code, args);
125 }
126 
127 void *
128 npf_bpf_compile(void *code, size_t size)
129 {
130 	return bpf_jit_generate(npf_bpfctx, code, size);
131 }
132 
133 bool
134 npf_bpf_validate(const void *code, size_t len)
135 {
136 	const size_t icount = len / sizeof(struct bpf_insn);
137 	return bpf_validate_ext(npf_bpfctx, code, icount) != 0;
138 }
139 
140 /*
141  * NPF_COP_L3: fetches layer 3 information.
142  */
143 static uint32_t
144 npf_cop_l3(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A)
145 {
146 	const npf_cache_t * const npc = (const npf_cache_t *)args->arg;
147 	const uint32_t ver = (npc->npc_alen & 4) | ((npc->npc_alen >> 4) * 6);
148 	uint32_t * const M = args->mem;
149 
150 	M[BPF_MW_IPVER] = ver;
151 	M[BPF_MW_L4OFF] = npc->npc_hlen;
152 	M[BPF_MW_L4PROTO] = npc->npc_proto;
153 	return ver; /* A <- IP version */
154 }
155 
156 #define	SRC_FLAG_BIT	(1U << 31)
157 
158 /*
159  * NPF_COP_TABLE: perform NPF table lookup.
160  *
161  *	A <- non-zero (true) if found and zero (false) otherwise
162  */
163 static uint32_t
164 npf_cop_table(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A)
165 {
166 	const npf_cache_t * const npc = (const npf_cache_t *)args->arg;
167 	npf_tableset_t *tblset = npf_config_tableset();
168 	const uint32_t tid = A & (SRC_FLAG_BIT - 1);
169 	const npf_addr_t *addr;
170 	npf_table_t *t;
171 
172 	KASSERT(npf_iscached(npc, NPC_IP46));
173 
174 	if ((t = npf_tableset_getbyid(tblset, tid)) == NULL) {
175 		return 0;
176 	}
177 	addr = npc->npc_ips[(A & SRC_FLAG_BIT) ? NPF_SRC : NPF_DST];
178 	return npf_table_lookup(t, npc->npc_alen, addr) == 0;
179 }
180