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