Annotation of src/sys/net/npf/npf_rproc.c, Revision 1.18
1.1 rmind 1: /*-
1.6 rmind 2: * Copyright (c) 2009-2013 The NetBSD Foundation, Inc.
1.1 rmind 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: /*
1.3 rmind 31: * NPF extension and rule procedure interface.
1.1 rmind 32: */
33:
1.14 christos 34: #ifdef _KERNEL
1.1 rmind 35: #include <sys/cdefs.h>
1.18 ! kamil 36: __KERNEL_RCSID(0, "$NetBSD$");
1.1 rmind 37:
38: #include <sys/param.h>
1.2 rmind 39: #include <sys/types.h>
1.1 rmind 40:
41: #include <sys/atomic.h>
42: #include <sys/kmem.h>
1.3 rmind 43: #include <sys/mutex.h>
1.7 christos 44: #include <sys/module.h>
1.14 christos 45: #endif
1.1 rmind 46:
47: #include "npf_impl.h"
48:
1.3 rmind 49: #define EXT_NAME_LEN 32
50:
51: typedef struct npf_ext {
52: char ext_callname[EXT_NAME_LEN];
53: LIST_ENTRY(npf_ext) ext_entry;
54: const npf_ext_ops_t * ext_ops;
55: unsigned ext_refcnt;
56: } npf_ext_t;
57:
1.6 rmind 58: struct npf_rprocset {
59: LIST_HEAD(, npf_rproc) rps_list;
60: };
61:
1.3 rmind 62: #define RPROC_NAME_LEN 32
63: #define RPROC_EXT_COUNT 16
1.1 rmind 64:
65: struct npf_rproc {
1.6 rmind 66: /* Flags and reference count. */
67: uint32_t rp_flags;
1.1 rmind 68: u_int rp_refcnt;
1.6 rmind 69:
1.3 rmind 70: /* Associated extensions and their metadata . */
71: unsigned rp_ext_count;
72: npf_ext_t * rp_ext[RPROC_EXT_COUNT];
73: void * rp_ext_meta[RPROC_EXT_COUNT];
1.6 rmind 74:
75: /* Name of the procedure and list entry. */
76: char rp_name[RPROC_NAME_LEN];
77: LIST_ENTRY(npf_rproc) rp_entry;
1.1 rmind 78: };
79:
1.3 rmind 80: void
1.14 christos 81: npf_ext_init(npf_t *npf)
1.3 rmind 82: {
1.14 christos 83: mutex_init(&npf->ext_lock, MUTEX_DEFAULT, IPL_NONE);
84: LIST_INIT(&npf->ext_list);
1.3 rmind 85: }
86:
87: void
1.14 christos 88: npf_ext_fini(npf_t *npf)
1.3 rmind 89: {
1.14 christos 90: KASSERT(LIST_EMPTY(&npf->ext_list));
91: mutex_destroy(&npf->ext_lock);
1.3 rmind 92: }
93:
94: /*
95: * NPF extension management for the rule procedures.
96: */
97:
1.8 christos 98: static const char npf_ext_prefix[] = "npf_ext_";
99: #define NPF_EXT_PREFLEN (sizeof(npf_ext_prefix) - 1)
100:
1.3 rmind 101: static npf_ext_t *
1.14 christos 102: npf_ext_lookup(npf_t *npf, const char *name, bool autoload)
1.3 rmind 103: {
1.8 christos 104: npf_ext_t *ext;
105: char modname[RPROC_NAME_LEN + NPF_EXT_PREFLEN];
1.9 christos 106: int error;
1.3 rmind 107:
1.14 christos 108: KASSERT(mutex_owned(&npf->ext_lock));
1.3 rmind 109:
1.8 christos 110: again:
1.14 christos 111: LIST_FOREACH(ext, &npf->ext_list, ext_entry)
1.3 rmind 112: if (strcmp(ext->ext_callname, name) == 0)
113: break;
1.8 christos 114:
1.9 christos 115: if (ext != NULL || !autoload)
1.8 christos 116: return ext;
117:
1.14 christos 118: mutex_exit(&npf->ext_lock);
1.9 christos 119: autoload = false;
1.8 christos 120: snprintf(modname, sizeof(modname), "%s%s", npf_ext_prefix, name);
121: error = module_autoload(modname, MODULE_CLASS_MISC);
1.14 christos 122: mutex_enter(&npf->ext_lock);
1.8 christos 123:
124: if (error)
125: return NULL;
126: goto again;
1.3 rmind 127: }
128:
129: void *
1.14 christos 130: npf_ext_register(npf_t *npf, const char *name, const npf_ext_ops_t *ops)
1.3 rmind 131: {
132: npf_ext_t *ext;
133:
134: ext = kmem_zalloc(sizeof(npf_ext_t), KM_SLEEP);
135: strlcpy(ext->ext_callname, name, EXT_NAME_LEN);
136: ext->ext_ops = ops;
137:
1.14 christos 138: mutex_enter(&npf->ext_lock);
139: if (npf_ext_lookup(npf, name, false)) {
140: mutex_exit(&npf->ext_lock);
1.3 rmind 141: kmem_free(ext, sizeof(npf_ext_t));
142: return NULL;
143: }
1.14 christos 144: LIST_INSERT_HEAD(&npf->ext_list, ext, ext_entry);
145: mutex_exit(&npf->ext_lock);
1.3 rmind 146:
147: return (void *)ext;
148: }
149:
150: int
1.14 christos 151: npf_ext_unregister(npf_t *npf, void *extid)
1.3 rmind 152: {
153: npf_ext_t *ext = extid;
154:
155: /*
156: * Check if in-use first (re-check with the lock held).
157: */
158: if (ext->ext_refcnt) {
159: return EBUSY;
160: }
161:
1.14 christos 162: mutex_enter(&npf->ext_lock);
1.3 rmind 163: if (ext->ext_refcnt) {
1.14 christos 164: mutex_exit(&npf->ext_lock);
1.3 rmind 165: return EBUSY;
166: }
1.14 christos 167: KASSERT(npf_ext_lookup(npf, ext->ext_callname, false));
1.3 rmind 168: LIST_REMOVE(ext, ext_entry);
1.14 christos 169: mutex_exit(&npf->ext_lock);
1.3 rmind 170:
171: kmem_free(ext, sizeof(npf_ext_t));
172: return 0;
173: }
174:
175: int
1.14 christos 176: npf_ext_construct(npf_t *npf, const char *name,
1.17 rmind 177: npf_rproc_t *rp, const nvlist_t *params)
1.3 rmind 178: {
179: const npf_ext_ops_t *extops;
180: npf_ext_t *ext;
181: unsigned i;
182: int error;
183:
184: if (rp->rp_ext_count >= RPROC_EXT_COUNT) {
185: return ENOSPC;
186: }
187:
1.14 christos 188: mutex_enter(&npf->ext_lock);
189: ext = npf_ext_lookup(npf, name, true);
1.3 rmind 190: if (ext) {
191: atomic_inc_uint(&ext->ext_refcnt);
192: }
1.14 christos 193: mutex_exit(&npf->ext_lock);
1.4 mlelstv 194:
1.3 rmind 195: if (!ext) {
196: return ENOENT;
197: }
198:
1.4 mlelstv 199: extops = ext->ext_ops;
200: KASSERT(extops != NULL);
201:
1.3 rmind 202: error = extops->ctor(rp, params);
203: if (error) {
204: atomic_dec_uint(&ext->ext_refcnt);
205: return error;
206: }
207: i = rp->rp_ext_count++;
208: rp->rp_ext[i] = ext;
209: return 0;
210: }
211:
212: /*
213: * Rule procedure management.
214: */
215:
1.6 rmind 216: npf_rprocset_t *
217: npf_rprocset_create(void)
218: {
219: npf_rprocset_t *rpset;
220:
221: rpset = kmem_zalloc(sizeof(npf_rprocset_t), KM_SLEEP);
222: LIST_INIT(&rpset->rps_list);
223: return rpset;
224: }
225:
226: void
227: npf_rprocset_destroy(npf_rprocset_t *rpset)
228: {
229: npf_rproc_t *rp;
230:
231: while ((rp = LIST_FIRST(&rpset->rps_list)) != NULL) {
232: LIST_REMOVE(rp, rp_entry);
233: npf_rproc_release(rp);
234: }
235: kmem_free(rpset, sizeof(npf_rprocset_t));
236: }
237:
238: /*
239: * npf_rproc_lookup: find a rule procedure by the name.
240: */
241: npf_rproc_t *
242: npf_rprocset_lookup(npf_rprocset_t *rpset, const char *name)
243: {
244: npf_rproc_t *rp;
245:
246: LIST_FOREACH(rp, &rpset->rps_list, rp_entry) {
247: if (strncmp(rp->rp_name, name, RPROC_NAME_LEN) == 0)
248: break;
249: }
1.8 christos 250: return rp;
1.6 rmind 251: }
252:
253: /*
254: * npf_rproc_insert: insert a new rule procedure into the set.
255: */
256: void
257: npf_rprocset_insert(npf_rprocset_t *rpset, npf_rproc_t *rp)
258: {
259: LIST_INSERT_HEAD(&rpset->rps_list, rp, rp_entry);
260: }
261:
1.12 rmind 262: int
1.17 rmind 263: npf_rprocset_export(const npf_rprocset_t *rpset, nvlist_t *npf_dict)
1.12 rmind 264: {
265: const npf_rproc_t *rp;
266:
267: LIST_FOREACH(rp, &rpset->rps_list, rp_entry) {
1.17 rmind 268: nvlist_t *rproc = nvlist_create(0);
269: #if 0 // FIXME/TODO
270: for (unsigned i = 0; i < rp->rp_ext_count; i++) {
271: nvlist_t *meta = rp->rp_ext_meta[i];
272: ...
273: nvlist_append_nvlist_array(rproc, "extcalls", meta);
274: }
275: #endif
276: nvlist_add_string(rproc, "name", rp->rp_name);
277: nvlist_add_number(rproc, "flags", rp->rp_flags);
278: nvlist_append_nvlist_array(npf_dict, "rprocs", rproc);
279: nvlist_destroy(rproc);
1.12 rmind 280: }
281: return 0;
282: }
283:
1.3 rmind 284: /*
285: * npf_rproc_create: construct a new rule procedure, lookup and associate
286: * the extension calls with it.
287: */
1.1 rmind 288: npf_rproc_t *
1.17 rmind 289: npf_rproc_create(const nvlist_t *rproc)
1.1 rmind 290: {
1.3 rmind 291: const char *name;
1.1 rmind 292: npf_rproc_t *rp;
1.3 rmind 293:
1.17 rmind 294: if ((name = dnvlist_get_string(rproc, "name", NULL)) == NULL) {
1.3 rmind 295: return NULL;
296: }
1.1 rmind 297:
1.2 rmind 298: rp = kmem_intr_zalloc(sizeof(npf_rproc_t), KM_SLEEP);
1.1 rmind 299: rp->rp_refcnt = 1;
300:
1.3 rmind 301: strlcpy(rp->rp_name, name, RPROC_NAME_LEN);
1.17 rmind 302: rp->rp_flags = dnvlist_get_number(rproc, "flags", 0);
1.1 rmind 303: return rp;
304: }
305:
1.3 rmind 306: /*
307: * npf_rproc_acquire: acquire the reference on the rule procedure.
308: */
1.1 rmind 309: void
310: npf_rproc_acquire(npf_rproc_t *rp)
311: {
312: atomic_inc_uint(&rp->rp_refcnt);
313: }
314:
1.3 rmind 315: /*
1.15 christos 316: * npf_rproc_getname: return the name of the given rproc
317: */
318: const char *
319: npf_rproc_getname(const npf_rproc_t *rp)
320: {
321: return rp->rp_name;
322: }
323:
324: /*
1.3 rmind 325: * npf_rproc_release: drop the reference count and destroy the rule
326: * procedure on the last reference.
327: */
1.1 rmind 328: void
329: npf_rproc_release(npf_rproc_t *rp)
330: {
331:
332: KASSERT(rp->rp_refcnt > 0);
333: if (atomic_dec_uint_nv(&rp->rp_refcnt) != 0) {
334: return;
335: }
1.3 rmind 336: /* XXXintr */
337: for (unsigned i = 0; i < rp->rp_ext_count; i++) {
338: npf_ext_t *ext = rp->rp_ext[i];
339: const npf_ext_ops_t *extops = ext->ext_ops;
340:
341: extops->dtor(rp, rp->rp_ext_meta[i]);
342: atomic_dec_uint(&ext->ext_refcnt);
343: }
1.2 rmind 344: kmem_intr_free(rp, sizeof(npf_rproc_t));
1.1 rmind 345: }
346:
347: void
1.3 rmind 348: npf_rproc_assign(npf_rproc_t *rp, void *params)
1.1 rmind 349: {
1.3 rmind 350: unsigned i = rp->rp_ext_count;
351:
352: /* Note: params may be NULL. */
353: KASSERT(i < RPROC_EXT_COUNT);
354: rp->rp_ext_meta[i] = params;
355: }
356:
357: /*
358: * npf_rproc_run: run the rule procedure by executing each extension call.
359: *
360: * => Reference on the rule procedure must be held.
361: */
1.10 jakllsch 362: bool
1.16 christos 363: npf_rproc_run(npf_cache_t *npc, npf_rproc_t *rp, const npf_match_info_t *mi,
364: int *decision)
1.3 rmind 365: {
366: const unsigned extcount = rp->rp_ext_count;
1.1 rmind 367:
1.11 rmind 368: KASSERT(!nbuf_flag_p(npc->npc_nbuf, NBUF_DATAREF_RESET));
1.1 rmind 369: KASSERT(rp->rp_refcnt > 0);
370:
1.3 rmind 371: for (unsigned i = 0; i < extcount; i++) {
372: const npf_ext_t *ext = rp->rp_ext[i];
373: const npf_ext_ops_t *extops = ext->ext_ops;
1.1 rmind 374:
1.3 rmind 375: KASSERT(ext->ext_refcnt > 0);
1.16 christos 376: if (!extops->proc(npc, rp->rp_ext_meta[i], mi, decision)) {
1.10 jakllsch 377: return false;
378: }
1.5 rmind 379:
1.11 rmind 380: if (nbuf_flag_p(npc->npc_nbuf, NBUF_DATAREF_RESET)) {
381: npf_recache(npc);
1.5 rmind 382: }
1.1 rmind 383: }
1.10 jakllsch 384:
385: return true;
1.1 rmind 386: }
CVSweb <webmaster@jp.NetBSD.org>