1 /* $NetBSD: npf_ext_rndblock.c,v 1.6 2016/12/26 23:05:06 christos Exp $ */ 2 3 /*- 4 * Copyright (c) 2012 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 /* 30 * NPF random blocking extension - kernel module. 31 * This is also a demo extension. 32 */ 33 34 #ifdef _KERNEL 35 #include <sys/cdefs.h> 36 __KERNEL_RCSID(0, "$NetBSD: npf_ext_rndblock.c,v 1.6 2016/12/26 23:05:06 christos Exp $"); 37 38 #include <sys/types.h> 39 #include <sys/cprng.h> 40 #include <sys/atomic.h> 41 #include <sys/module.h> 42 #include <sys/kmem.h> 43 #endif 44 45 #include "npf_impl.h" 46 47 /* 48 * NPF extension module definition and the identifier. 49 */ 50 NPF_EXT_MODULE(npf_ext_rndblock, ""); 51 52 #define NPFEXT_RNDBLOCK_VER 1 53 54 static void * npf_ext_rndblock_id; 55 56 #define PERCENTAGE_BASE 10000 57 58 /* 59 * Meta-data structure, containing parameters. 60 */ 61 typedef struct { 62 unsigned int mod; 63 unsigned long counter; 64 unsigned int percentage; 65 } npf_ext_rndblock_t; 66 67 /* 68 * npf_ext_rndblock_ctor: a constructor to parse and store any parameters 69 * associated with a rule procedure, which is being newly created. 70 */ 71 static int 72 npf_ext_rndblock_ctor(npf_rproc_t *rp, prop_dictionary_t params) 73 { 74 npf_ext_rndblock_t *meta; 75 76 /* 77 * Allocate and a associate a structure for the parameter 78 * and our meta-data. 79 */ 80 meta = kmem_zalloc(sizeof(npf_ext_rndblock_t), KM_SLEEP); 81 prop_dictionary_get_uint32(params, "mod", &meta->mod); 82 prop_dictionary_get_uint32(params, "percentage", &meta->percentage); 83 npf_rproc_assign(rp, meta); 84 85 return 0; 86 } 87 88 /* 89 * npf_ext_rndblock_dtor: a destructor for our rule procedure. 90 */ 91 static void 92 npf_ext_rndblock_dtor(npf_rproc_t *rp, void *meta) 93 { 94 /* Free our meta-data, associated with the procedure. */ 95 kmem_free(meta, sizeof(npf_ext_rndblock_t)); 96 } 97 98 /* 99 * npf_ext_rndblock: main routine implementing the extension functionality. 100 */ 101 static bool 102 npf_ext_rndblock(npf_cache_t *npc, void *meta, int *decision) 103 { 104 npf_ext_rndblock_t *rndblock = meta; 105 unsigned long c; 106 107 /* Skip, if already blocking. */ 108 if (*decision == NPF_DECISION_BLOCK) { 109 return true; 110 } 111 112 /* 113 * Sample demo: 114 * 115 * Drop the packets according to the given module or percentage. 116 * 117 * Rule procedures may be executed concurrently in an SMP system. 118 * Use atomic operation to increment the counter. 119 */ 120 c = atomic_inc_ulong_nv(&rndblock->counter); 121 122 if (rndblock->mod) { 123 if ((c % rndblock->mod) == 0) { 124 *decision = NPF_DECISION_BLOCK; 125 } 126 } 127 128 if (rndblock->percentage) { 129 uint32_t w = cprng_fast32() % PERCENTAGE_BASE; 130 if (w <= rndblock->percentage) { 131 *decision = NPF_DECISION_BLOCK; 132 } 133 } 134 135 return true; 136 } 137 138 /* 139 * Module interface. 140 */ 141 static int 142 npf_ext_rndblock_modcmd(modcmd_t cmd, void *arg) 143 { 144 static const npf_ext_ops_t npf_rndblock_ops = { 145 .version = NPFEXT_RNDBLOCK_VER, 146 .ctx = NULL, 147 .ctor = npf_ext_rndblock_ctor, 148 .dtor = npf_ext_rndblock_dtor, 149 .proc = npf_ext_rndblock 150 }; 151 npf_t *npf = npf_getkernctx(); 152 153 switch (cmd) { 154 case MODULE_CMD_INIT: 155 /* 156 * Initialise the NPF extension module. Register the 157 * "rndblock" extensions calls (constructor, destructor, 158 * the processing * routine, etc). 159 */ 160 npf_ext_rndblock_id = npf_ext_register(npf, "rndblock", 161 &npf_rndblock_ops); 162 return npf_ext_rndblock_id ? 0 : EEXIST; 163 164 case MODULE_CMD_FINI: 165 /* 166 * Unregister our rndblock extension. NPF may return an 167 * if there are references and it cannot drain them. 168 */ 169 return npf_ext_unregister(npf, npf_ext_rndblock_id); 170 171 case MODULE_CMD_AUTOUNLOAD: 172 /* Allow auto-unload only if NPF permits it. */ 173 return npf_autounload_p() ? 0 : EBUSY; 174 175 default: 176 return ENOTTY; 177 } 178 return 0; 179 } 180