Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/netpfil/ipfw/ip_fw_table_value.c
39482 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* Copyright (c) 2014-2025 Yandex LLC
5
* Copyright (c) 2014 Alexander V. Chernikov
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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26
* SUCH DAMAGE.
27
*/
28
29
#include <sys/cdefs.h>
30
/*
31
* Multi-field value support for ipfw tables.
32
*
33
* This file contains necessary functions to convert
34
* large multi-field values into u32 indices suitable to be fed
35
* to various table algorithms. Other machinery like proper refcounting,
36
* internal structures resizing are also kept here.
37
*/
38
39
#include "opt_ipfw.h"
40
41
#include <sys/param.h>
42
#include <sys/systm.h>
43
#include <sys/malloc.h>
44
#include <sys/kernel.h>
45
#include <sys/hash.h>
46
#include <sys/lock.h>
47
#include <sys/rwlock.h>
48
#include <sys/rmlock.h>
49
#include <sys/socket.h>
50
#include <sys/socketvar.h>
51
#include <sys/queue.h>
52
#include <net/if.h> /* ip_fw.h requires IFNAMSIZ */
53
54
#include <netinet/in.h>
55
#include <netinet/ip_var.h> /* struct ipfw_rule_ref */
56
#include <netinet/ip_fw.h>
57
58
#include <netpfil/ipfw/ip_fw_private.h>
59
#include <netpfil/ipfw/ip_fw_table.h>
60
61
static uint32_t hash_table_value(struct namedobj_instance *ni, const void *key,
62
uint32_t kopt);
63
static int cmp_table_value(struct named_object *no, const void *key,
64
uint32_t kopt);
65
66
static int list_table_values(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
67
struct sockopt_data *sd);
68
69
static struct ipfw_sopt_handler scodes[] = {
70
{ IP_FW_TABLE_VLIST, IP_FW3_OPVER, HDIR_GET, list_table_values },
71
};
72
73
#define CHAIN_TO_VI(chain) (CHAIN_TO_TCFG(chain)->valhash)
74
75
struct table_val_link
76
{
77
struct named_object no;
78
struct table_value *pval; /* Pointer to real table value */
79
};
80
#define VALDATA_START_SIZE 64 /* Allocate 64-items array by default */
81
#define VALDATA_HASH_SIZE 65536
82
83
struct vdump_args {
84
struct ip_fw_chain *ch;
85
struct sockopt_data *sd;
86
struct table_value *pval;
87
int error;
88
};
89
90
static uint32_t
91
hash_table_value(struct namedobj_instance *ni, const void *key, uint32_t kopt)
92
{
93
94
return (hash32_buf(key, 56, 0));
95
}
96
97
static int
98
cmp_table_value(struct named_object *no, const void *key, uint32_t kopt)
99
{
100
101
return (memcmp(((struct table_val_link *)no)->pval, key, 56));
102
}
103
104
static void
105
mask_table_value(struct table_value *src, struct table_value *dst,
106
uint32_t mask)
107
{
108
#define _MCPY(f, b) if ((mask & (b)) != 0) { dst->f = src->f; }
109
110
memset(dst, 0, sizeof(*dst));
111
_MCPY(tag, IPFW_VTYPE_TAG);
112
_MCPY(pipe, IPFW_VTYPE_PIPE);
113
_MCPY(divert, IPFW_VTYPE_DIVERT);
114
_MCPY(skipto, IPFW_VTYPE_SKIPTO);
115
_MCPY(netgraph, IPFW_VTYPE_NETGRAPH);
116
_MCPY(fib, IPFW_VTYPE_FIB);
117
_MCPY(nat, IPFW_VTYPE_NAT);
118
_MCPY(limit, IPFW_VTYPE_LIMIT);
119
_MCPY(mark, IPFW_VTYPE_MARK);
120
_MCPY(dscp, IPFW_VTYPE_DSCP);
121
_MCPY(nh4, IPFW_VTYPE_NH4);
122
_MCPY(nh6, IPFW_VTYPE_NH6);
123
_MCPY(zoneid, IPFW_VTYPE_NH6);
124
#undef _MCPY
125
}
126
127
static void
128
get_value_ptrs(struct ip_fw_chain *ch, struct table_config *tc, int vshared,
129
struct table_value **ptv, struct namedobj_instance **pvi)
130
{
131
struct table_value *pval;
132
struct namedobj_instance *vi;
133
134
if (vshared != 0) {
135
pval = (struct table_value *)ch->valuestate;
136
vi = CHAIN_TO_VI(ch);
137
} else {
138
pval = NULL;
139
vi = NULL;
140
//pval = (struct table_value *)&tc->ti.data;
141
}
142
143
if (ptv != NULL)
144
*ptv = pval;
145
if (pvi != NULL)
146
*pvi = vi;
147
}
148
149
/*
150
* Update pointers to real vaues after @pval change.
151
*/
152
static int
153
update_tvalue(struct namedobj_instance *ni, struct named_object *no, void *arg)
154
{
155
struct vdump_args *da;
156
struct table_val_link *ptv;
157
struct table_value *pval;
158
159
da = (struct vdump_args *)arg;
160
ptv = (struct table_val_link *)no;
161
162
pval = da->pval;
163
ptv->pval = &pval[ptv->no.kidx];
164
ptv->no.name = (char *)&pval[ptv->no.kidx];
165
return (0);
166
}
167
168
/*
169
* Grows value storage shared among all tables.
170
* Drops/reacquires UH locks.
171
* Notifies other running adds on @ch shared storage resize.
172
* Note function does not guarantee that free space
173
* will be available after invocation, so one caller needs
174
* to roll cycle himself.
175
*
176
* Returns 0 if case of no errors.
177
*/
178
static int
179
resize_shared_value_storage(struct ip_fw_chain *ch)
180
{
181
struct tables_config *tcfg;
182
struct namedobj_instance *vi;
183
struct table_value *pval, *valuestate, *old_valuestate;
184
void *new_idx;
185
struct vdump_args da;
186
int new_blocks;
187
int val_size, val_size_old;
188
189
IPFW_UH_WLOCK_ASSERT(ch);
190
191
valuestate = NULL;
192
new_idx = NULL;
193
194
pval = (struct table_value *)ch->valuestate;
195
vi = CHAIN_TO_VI(ch);
196
tcfg = CHAIN_TO_TCFG(ch);
197
198
val_size = tcfg->val_size * 2;
199
200
if (val_size == (1 << 30))
201
return (ENOSPC);
202
203
IPFW_UH_WUNLOCK(ch);
204
205
valuestate = malloc(sizeof(struct table_value) * val_size, M_IPFW,
206
M_WAITOK | M_ZERO);
207
ipfw_objhash_bitmap_alloc(val_size, (void *)&new_idx,
208
&new_blocks);
209
210
IPFW_UH_WLOCK(ch);
211
212
/*
213
* Check if we still need to resize
214
*/
215
if (tcfg->val_size >= val_size)
216
goto done;
217
218
/* Update pointers and notify everyone we're changing @ch */
219
pval = (struct table_value *)ch->valuestate;
220
rollback_toperation_state(ch, ch);
221
222
/* Good. Let's merge */
223
memcpy(valuestate, pval, sizeof(struct table_value) * tcfg->val_size);
224
ipfw_objhash_bitmap_merge(CHAIN_TO_VI(ch), &new_idx, &new_blocks);
225
226
IPFW_WLOCK(ch);
227
/* Change pointers */
228
old_valuestate = ch->valuestate;
229
ch->valuestate = valuestate;
230
valuestate = old_valuestate;
231
ipfw_objhash_bitmap_swap(CHAIN_TO_VI(ch), &new_idx, &new_blocks);
232
233
val_size_old = tcfg->val_size;
234
tcfg->val_size = val_size;
235
val_size = val_size_old;
236
IPFW_WUNLOCK(ch);
237
/* Update pointers to reflect resize */
238
memset(&da, 0, sizeof(da));
239
da.pval = (struct table_value *)ch->valuestate;
240
ipfw_objhash_foreach(vi, update_tvalue, &da);
241
242
done:
243
free(valuestate, M_IPFW);
244
ipfw_objhash_bitmap_free(new_idx, new_blocks);
245
246
return (0);
247
}
248
249
/*
250
* Drops reference for table value with index @kidx, stored in @pval and
251
* @vi. Frees value if it has no references.
252
*/
253
static void
254
unref_table_value(struct namedobj_instance *vi, struct table_value *pval,
255
uint32_t kidx)
256
{
257
struct table_val_link *ptvl;
258
259
KASSERT(pval[kidx].refcnt > 0, ("Refcount is 0 on kidx %d", kidx));
260
if (--pval[kidx].refcnt > 0)
261
return;
262
263
/* Last reference, delete item */
264
ptvl = (struct table_val_link *)ipfw_objhash_lookup_kidx(vi, kidx);
265
KASSERT(ptvl != NULL, ("lookup on value kidx %d failed", kidx));
266
ipfw_objhash_del(vi, &ptvl->no);
267
ipfw_objhash_free_idx(vi, kidx);
268
free(ptvl, M_IPFW);
269
}
270
271
struct flush_args {
272
struct ip_fw_chain *ch;
273
struct table_algo *ta;
274
struct table_info *ti;
275
void *astate;
276
ipfw_obj_tentry tent;
277
};
278
279
static int
280
unref_table_value_cb(void *e, void *arg)
281
{
282
struct flush_args *fa;
283
struct ip_fw_chain *ch;
284
struct table_algo *ta;
285
ipfw_obj_tentry *tent;
286
int error;
287
288
fa = (struct flush_args *)arg;
289
290
ta = fa->ta;
291
memset(&fa->tent, 0, sizeof(fa->tent));
292
tent = &fa->tent;
293
error = ta->dump_tentry(fa->astate, fa->ti, e, tent);
294
if (error != 0)
295
return (error);
296
297
ch = fa->ch;
298
299
unref_table_value(CHAIN_TO_VI(ch),
300
(struct table_value *)ch->valuestate, tent->v.kidx);
301
302
return (0);
303
}
304
305
/*
306
* Drop references for each value used in @tc.
307
*/
308
void
309
ipfw_unref_table_values(struct ip_fw_chain *ch, struct table_config *tc,
310
struct table_algo *ta, void *astate, struct table_info *ti)
311
{
312
struct flush_args fa;
313
314
IPFW_UH_WLOCK_ASSERT(ch);
315
316
memset(&fa, 0, sizeof(fa));
317
fa.ch = ch;
318
fa.ta = ta;
319
fa.astate = astate;
320
fa.ti = ti;
321
322
ta->foreach(astate, ti, unref_table_value_cb, &fa);
323
}
324
325
/*
326
* Table operation state handler.
327
* Called when we are going to change something in @tc which
328
* may lead to inconsistencies in on-going table data addition.
329
*
330
* Here we rollback all already committed state (table values, currently)
331
* and set "modified" field to non-zero value to indicate
332
* that we need to restart original operation.
333
*/
334
void
335
rollback_table_values(struct tableop_state *ts)
336
{
337
struct ip_fw_chain *ch;
338
struct table_value *pval;
339
struct tentry_info *ptei;
340
struct namedobj_instance *vi;
341
int i;
342
343
ch = ts->ch;
344
345
IPFW_UH_WLOCK_ASSERT(ch);
346
347
/* Get current table value pointer */
348
get_value_ptrs(ch, ts->tc, ts->vshared, &pval, &vi);
349
350
for (i = 0; i < ts->count; i++) {
351
ptei = &ts->tei[i];
352
353
if (ptei->value == 0)
354
continue;
355
356
unref_table_value(vi, pval, ptei->value);
357
}
358
}
359
360
/*
361
* Allocate new value index in either shared or per-table array.
362
* Function may drop/reacquire UH lock.
363
*
364
* Returns 0 on success.
365
*/
366
static int
367
alloc_table_vidx(struct ip_fw_chain *ch, struct tableop_state *ts,
368
struct namedobj_instance *vi, uint32_t *pvidx, uint8_t flags)
369
{
370
int error, vlimit;
371
uint32_t vidx;
372
373
IPFW_UH_WLOCK_ASSERT(ch);
374
375
error = ipfw_objhash_alloc_idx(vi, &vidx);
376
if (error != 0) {
377
/*
378
* We need to resize array. This involves
379
* lock/unlock, so we need to check "modified"
380
* state.
381
*/
382
ts->opstate.func(ts->tc, &ts->opstate);
383
error = resize_shared_value_storage(ch);
384
return (error); /* ts->modified should be set, we will restart */
385
}
386
387
vlimit = ts->ta->vlimit;
388
if (vlimit != 0 && vidx >= vlimit && !(flags & IPFW_CTF_ATOMIC)) {
389
/*
390
* Algorithm is not able to store given index.
391
* We have to rollback state, start using
392
* per-table value array or return error
393
* if we're already using it.
394
*/
395
if (ts->vshared != 0) {
396
/* shared -> per-table */
397
return (ENOSPC); /* TODO: proper error */
398
}
399
400
/* per-table. Fail for now. */
401
return (ENOSPC); /* TODO: proper error */
402
}
403
404
*pvidx = vidx;
405
return (0);
406
}
407
408
/*
409
* Drops value reference for unused values (updates, deletes, partially
410
* successful adds or rollbacks).
411
*/
412
void
413
ipfw_garbage_table_values(struct ip_fw_chain *ch, struct table_config *tc,
414
struct tentry_info *tei, uint32_t count, int rollback)
415
{
416
int i;
417
struct tentry_info *ptei;
418
struct table_value *pval;
419
struct namedobj_instance *vi;
420
421
/*
422
* We have two slightly different ADD cases here:
423
* either (1) we are successful / partially successful,
424
* in that case we need
425
* * to ignore ADDED entries values
426
* * rollback every other values if atomicity is not
427
* * required (either UPDATED since old value has been
428
* stored there, or some failure like EXISTS or LIMIT
429
* or simply "ignored" case.
430
*
431
* (2): atomic rollback of partially successful operation
432
* in that case we simply need to unref all entries.
433
*
434
* DELETE case is simpler: no atomic support there, so
435
* we simply unref all non-zero values.
436
*/
437
438
/*
439
* Get current table value pointers.
440
* XXX: Properly read vshared
441
*/
442
get_value_ptrs(ch, tc, 1, &pval, &vi);
443
444
for (i = 0; i < count; i++) {
445
ptei = &tei[i];
446
447
if (ptei->value == 0) {
448
/*
449
* We may be deleting non-existing record.
450
* Skip.
451
*/
452
continue;
453
}
454
455
if ((ptei->flags & TEI_FLAGS_ADDED) != 0 && rollback == 0) {
456
ptei->value = 0;
457
continue;
458
}
459
460
unref_table_value(vi, pval, ptei->value);
461
ptei->value = 0;
462
}
463
}
464
465
/*
466
* Main function used to link values of entries going to be added,
467
* to the index. Since we may perform many UH locks drops/acquires,
468
* handle changes by checking tablestate "modified" field.
469
*
470
* Success: return 0.
471
*/
472
int
473
ipfw_link_table_values(struct ip_fw_chain *ch, struct tableop_state *ts,
474
uint8_t flags)
475
{
476
int error, i, found;
477
struct namedobj_instance *vi;
478
struct table_config *tc;
479
struct tentry_info *tei, *ptei;
480
uint32_t count, vidx, vlimit;
481
struct table_val_link *ptv;
482
struct table_value tval, *pval;
483
484
/*
485
* Stage 1: reference all existing values and
486
* save their indices.
487
*/
488
IPFW_UH_WLOCK_ASSERT(ch);
489
get_value_ptrs(ch, ts->tc, ts->vshared, &pval, &vi);
490
491
error = 0;
492
found = 0;
493
vlimit = ts->ta->vlimit;
494
vidx = 0;
495
tc = ts->tc;
496
tei = ts->tei;
497
count = ts->count;
498
for (i = 0; i < count; i++) {
499
ptei = &tei[i];
500
ptei->value = 0; /* Ensure value is always 0 in the beginning */
501
mask_table_value(ptei->pvalue, &tval, ts->vmask);
502
ptv = (struct table_val_link *)ipfw_objhash_lookup_name(vi, 0,
503
(char *)&tval);
504
if (ptv == NULL)
505
continue;
506
/* Deal with vlimit later */
507
if (vlimit > 0 && vlimit <= ptv->no.kidx)
508
continue;
509
510
/* Value found. Bump refcount */
511
ptv->pval->refcnt++;
512
ptei->value = ptv->no.kidx;
513
found++;
514
}
515
516
if (ts->count == found) {
517
/* We've found all values , no need ts create new ones */
518
return (0);
519
}
520
521
/*
522
* we have added some state here, let's attach operation
523
* state ts the list ts be able ts rollback if necessary.
524
*/
525
add_toperation_state(ch, ts);
526
/* Ensure table won't disappear */
527
tc_ref(tc);
528
IPFW_UH_WUNLOCK(ch);
529
530
/*
531
* Stage 2: allocate objects for non-existing values.
532
*/
533
for (i = 0; i < count; i++) {
534
ptei = &tei[i];
535
if (ptei->value != 0)
536
continue;
537
if (ptei->ptv != NULL)
538
continue;
539
ptei->ptv = malloc(sizeof(struct table_val_link), M_IPFW,
540
M_WAITOK | M_ZERO);
541
}
542
543
/*
544
* Stage 3: allocate index numbers for new values
545
* and link them to index.
546
*/
547
IPFW_UH_WLOCK(ch);
548
tc_unref(tc);
549
del_toperation_state(ch, ts);
550
if (ts->modified != 0) {
551
/*
552
* In general, we should free all state/indexes here
553
* and return. However, we keep allocated state instead
554
* to ensure we achieve some progress on each restart.
555
*/
556
return (0);
557
}
558
559
KASSERT(pval == ch->valuestate, ("resize_storage() notify failure"));
560
561
/* Let's try to link values */
562
for (i = 0; i < count; i++) {
563
ptei = &tei[i];
564
565
/* Check if record has appeared */
566
mask_table_value(ptei->pvalue, &tval, ts->vmask);
567
ptv = (struct table_val_link *)ipfw_objhash_lookup_name(vi, 0,
568
(char *)&tval);
569
if (ptv != NULL) {
570
ptv->pval->refcnt++;
571
ptei->value = ptv->no.kidx;
572
continue;
573
}
574
575
/* May perform UH unlock/lock */
576
error = alloc_table_vidx(ch, ts, vi, &vidx, flags);
577
if (error != 0) {
578
ts->opstate.func(ts->tc, &ts->opstate);
579
return (error);
580
}
581
/* value storage resize has happened, return */
582
if (ts->modified != 0)
583
return (0);
584
585
/* Finally, we have allocated valid index, let's add entry */
586
ptei->value = vidx;
587
ptv = (struct table_val_link *)ptei->ptv;
588
ptei->ptv = NULL;
589
590
ptv->no.kidx = vidx;
591
ptv->no.name = (char *)&pval[vidx];
592
ptv->pval = &pval[vidx];
593
memcpy(ptv->pval, &tval, sizeof(struct table_value));
594
pval[vidx].refcnt = 1;
595
ipfw_objhash_add(vi, &ptv->no);
596
}
597
598
return (0);
599
}
600
601
/*
602
* Imports table value from current userland format.
603
* Saves value in kernel format to the same place.
604
*/
605
void
606
ipfw_import_table_value_v1(ipfw_table_value *iv)
607
{
608
struct table_value v;
609
610
memset(&v, 0, sizeof(v));
611
v.tag = iv->tag;
612
v.pipe = iv->pipe;
613
v.divert = iv->divert;
614
v.skipto = iv->skipto;
615
v.netgraph = iv->netgraph;
616
v.fib = iv->fib;
617
v.nat = iv->nat;
618
v.dscp = iv->dscp;
619
v.nh4 = iv->nh4;
620
v.nh6 = iv->nh6;
621
v.limit = iv->limit;
622
v.zoneid = iv->zoneid;
623
v.mark = iv->mark;
624
625
memcpy(iv, &v, sizeof(ipfw_table_value));
626
}
627
628
/*
629
* Export real table value @v to current userland format.
630
* Note that @v and @piv may point to the same memory.
631
*/
632
void
633
ipfw_export_table_value_v1(struct table_value *v, ipfw_table_value *piv)
634
{
635
ipfw_table_value iv;
636
637
memset(&iv, 0, sizeof(iv));
638
iv.tag = v->tag;
639
iv.pipe = v->pipe;
640
iv.divert = v->divert;
641
iv.skipto = v->skipto;
642
iv.netgraph = v->netgraph;
643
iv.fib = v->fib;
644
iv.nat = v->nat;
645
iv.dscp = v->dscp;
646
iv.limit = v->limit;
647
iv.nh4 = v->nh4;
648
iv.nh6 = v->nh6;
649
iv.zoneid = v->zoneid;
650
iv.mark = v->mark;
651
652
memcpy(piv, &iv, sizeof(iv));
653
}
654
655
/*
656
* Exports real value data into ipfw_table_value structure including refcnt.
657
*/
658
static int
659
dump_tvalue(struct namedobj_instance *ni, struct named_object *no, void *arg)
660
{
661
struct vdump_args *da;
662
struct table_val_link *ptv;
663
ipfw_table_value *v;
664
665
da = (struct vdump_args *)arg;
666
ptv = (struct table_val_link *)no;
667
668
v = (ipfw_table_value *)ipfw_get_sopt_space(da->sd, sizeof(*v));
669
/* Out of memory, returning */
670
if (v == NULL) {
671
da->error = ENOMEM;
672
return (ENOMEM);
673
}
674
675
ipfw_export_table_value_v1(ptv->pval, v);
676
v->refcnt = ptv->pval->refcnt;
677
v->kidx = ptv->no.kidx;
678
return (0);
679
}
680
681
/*
682
* Dumps all shared/table value data
683
* Data layout (v1)(current):
684
* Request: [ ipfw_obj_lheader ], size = ipfw_obj_lheader.size
685
* Reply: [ ipfw_obj_lheader ipfw_table_value x N ]
686
*
687
* Returns 0 on success
688
*/
689
static int
690
list_table_values(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
691
struct sockopt_data *sd)
692
{
693
struct _ipfw_obj_lheader *olh;
694
struct namedobj_instance *vi;
695
struct vdump_args da;
696
uint32_t count, size;
697
698
olh = (struct _ipfw_obj_lheader *)ipfw_get_sopt_header(sd,sizeof(*olh));
699
if (olh == NULL)
700
return (EINVAL);
701
if (sd->valsize < olh->size)
702
return (EINVAL);
703
704
IPFW_UH_RLOCK(ch);
705
vi = CHAIN_TO_VI(ch);
706
707
count = ipfw_objhash_count(vi);
708
size = count * sizeof(ipfw_table_value) + sizeof(ipfw_obj_lheader);
709
710
/* Fill in header regadless of buffer size */
711
olh->count = count;
712
olh->objsize = sizeof(ipfw_table_value);
713
714
if (size > olh->size) {
715
olh->size = size;
716
IPFW_UH_RUNLOCK(ch);
717
return (ENOMEM);
718
}
719
olh->size = size;
720
721
/*
722
* Do the actual value dump
723
*/
724
memset(&da, 0, sizeof(da));
725
da.ch = ch;
726
da.sd = sd;
727
ipfw_objhash_foreach(vi, dump_tvalue, &da);
728
729
IPFW_UH_RUNLOCK(ch);
730
731
return (0);
732
}
733
734
void
735
ipfw_table_value_init(struct ip_fw_chain *ch, int first)
736
{
737
struct tables_config *tcfg;
738
739
ch->valuestate = malloc(VALDATA_START_SIZE * sizeof(struct table_value),
740
M_IPFW, M_WAITOK | M_ZERO);
741
742
tcfg = ch->tblcfg;
743
744
tcfg->val_size = VALDATA_START_SIZE;
745
tcfg->valhash = ipfw_objhash_create(tcfg->val_size, VALDATA_HASH_SIZE);
746
ipfw_objhash_set_funcs(tcfg->valhash, hash_table_value,
747
cmp_table_value);
748
749
IPFW_ADD_SOPT_HANDLER(first, scodes);
750
}
751
752
static int
753
destroy_value(struct namedobj_instance *ni, struct named_object *no,
754
void *arg)
755
{
756
757
free(no, M_IPFW);
758
return (0);
759
}
760
761
void
762
ipfw_table_value_destroy(struct ip_fw_chain *ch, int last)
763
{
764
765
IPFW_DEL_SOPT_HANDLER(last, scodes);
766
767
free(ch->valuestate, M_IPFW);
768
ipfw_objhash_foreach(CHAIN_TO_VI(ch), destroy_value, ch);
769
ipfw_objhash_destroy(CHAIN_TO_VI(ch));
770
}
771
772