Use different approach for filling large datasets to userspace:

Instead of trying to allocate bing contiguous chunk of memory,
use intermediate-sized (page size) buffer as sliding window
reducing number of sooptcopyout() calls to perform.

This reduces dump functions complexity and provides additional
layer of abstraction.

User-visible api consists of 2 functions:
ipfw_get_sopt_space() - gets contigious amount of storage (or NULL)
and
ipfw_get_sopt_header() - the same, but zeroes the rest of the buffer.
This commit is contained in:
Alexander V. Chernikov 2014-06-27 10:07:00 +00:00
parent 9490a62716
commit 2d99a3497d
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/projects/ipfw/; revision=267954
4 changed files with 214 additions and 218 deletions

View File

@ -241,6 +241,15 @@ struct ip_fw_chain {
};
struct sockopt; /* used by tcp_var.h */
struct sockopt_data {
caddr_t kbuf; /* allocated buffer */
size_t ksize; /* given buffer size */
size_t koff; /* data already used */
size_t kavail; /* number of bytes available */
size_t ktotal; /* total bytes pushed */
struct sockopt *sopt; /* socket data */
size_t valsize; /* original data size */
};
/* Macro for working with various counters */
#define IPFW_INC_RULE_COUNTER(_cntr, _bytes) do { \
@ -333,6 +342,9 @@ int ipfw_ctl(struct sockopt *sopt);
int ipfw_chk(struct ip_fw_args *args);
void ipfw_reap_rules(struct ip_fw *head);
caddr_t ipfw_get_sopt_space(struct sockopt_data *sd, size_t needed);
caddr_t ipfw_get_sopt_header(struct sockopt_data *sd, size_t needed);
struct namedobj_instance;
struct named_object {

View File

@ -88,6 +88,7 @@ static uint32_t objhash_hash_name(struct namedobj_instance *ni, uint32_t set,
static uint32_t objhash_hash_val(struct namedobj_instance *ni, uint32_t set,
uint32_t val);
static int ipfw_flush_sopt_data(struct sockopt_data *sd);
MALLOC_DEFINE(M_IPFW, "IpFw/IpAcct", "IpFw/IpAcct chain's");
@ -989,6 +990,7 @@ ipfw_getrules(struct ip_fw_chain *chain, void *buf, size_t space)
#define IP_FW3_OPLENGTH(x) ((x)->sopt_valsize - sizeof(ip_fw3_opheader))
#define IP_FW3_OPTBUF 4096 /* page-size */
/**
* {set|get}sockopt parser.
*/
@ -1002,7 +1004,8 @@ ipfw_ctl(struct sockopt *sopt)
struct ip_fw_chain *chain;
u_int32_t rulenum[2];
uint32_t opt;
char xbuf[256];
char xbuf[128];
struct sockopt_data sdata;
ip_fw3_opheader *op3 = NULL;
struct rule_check_info ci;
@ -1026,15 +1029,40 @@ ipfw_ctl(struct sockopt *sopt)
/* Save original valsize before it is altered via sooptcopyin() */
valsize = sopt->sopt_valsize;
memset(&sdata, 0, sizeof(sdata));
if ((opt = sopt->sopt_name) == IP_FW3) {
/*
* Copy not less than sizeof(ip_fw3_opheader).
* We hope any IP_FW3 command will fit into 128-byte buffer.
/*
* Fill in sockopt_data structure that may be useful for
* IP_FW3 get requests
*/
if ((error = sooptcopyin(sopt, xbuf, sizeof(xbuf),
sizeof(ip_fw3_opheader))) != 0)
if (valsize <= sizeof(xbuf)) {
sdata.kbuf = xbuf;
sdata.ksize = sizeof(xbuf);
sdata.kavail = valsize;
} else {
if (valsize < IP_FW3_OPTBUF)
size = valsize;
else
size = IP_FW3_OPTBUF;
sdata.kbuf = malloc(size, M_TEMP, M_WAITOK | M_ZERO);
sdata.ksize = size;
sdata.kavail = size;
}
sdata.sopt = sopt;
sdata.valsize = valsize;
/*
* Copy either all request (if valsize < IP_FW3_OPTBUF)
* or first IP_FW3_OPTBUF bytes to guarantee most consumers
* that all necessary data has been copied).
* Anyway, copy not less than sizeof(ip_fw3_opheader).
*/
if ((error = sooptcopyin(sopt, sdata.kbuf, sdata.ksize,
sizeof(ip_fw3_opheader))) != 0)
return (error);
op3 = (ip_fw3_opheader *)xbuf;
op3 = (ip_fw3_opheader *)sdata.kbuf;
opt = op3->opcode;
}
@ -1205,19 +1233,19 @@ ipfw_ctl(struct sockopt *sopt)
}
case IP_FW_TABLE_XINFO: /* IP_FW3 */
error = ipfw_describe_table(chain, sopt, op3, valsize);
error = ipfw_describe_table(chain, &sdata);
break;
case IP_FW_TABLES_XGETSIZE: /* IP_FW3 */
error = ipfw_listsize_tables(chain, sopt, op3, valsize);
error = ipfw_listsize_tables(chain, &sdata);
break;
case IP_FW_TABLES_XLIST: /* IP_FW3 */
error = ipfw_list_tables(chain, sopt, op3, valsize);
error = ipfw_list_tables(chain, &sdata);
break;
case IP_FW_TABLE_XLIST: /* IP_FW3 */
error = ipfw_dump_table(chain, sopt, op3, valsize);
error = ipfw_dump_table(chain, op3, &sdata);
break;
case IP_FW_TABLE_XADD: /* IP_FW3 */
@ -1425,10 +1453,78 @@ ipfw_ctl(struct sockopt *sopt)
error = EINVAL;
}
if (op3 != NULL) {
/* Flush state and free buffers */
if (error == 0)
error = ipfw_flush_sopt_data(&sdata);
else
ipfw_flush_sopt_data(&sdata);
if (sdata.kbuf != xbuf)
free(sdata.kbuf, M_TEMP);
}
return (error);
#undef RULE_MAXSIZE
}
static int
ipfw_flush_sopt_data(struct sockopt_data *sd)
{
int error;
if (sd->koff == 0)
return (0);
if ((error = sooptcopyout(sd->sopt, sd->kbuf, sd->koff)) != 0)
return (error);
memset(sd->kbuf, 0, sd->ksize);
sd->ktotal += sd->koff;
sd->koff = 0;
if (sd->ktotal + sd->ksize < sd->valsize)
sd->kavail = sd->ksize;
else
sd->kavail = sd->valsize - sd->ktotal;
return (0);
}
caddr_t
ipfw_get_sopt_space(struct sockopt_data *sd, size_t needed)
{
int error;
caddr_t addr;
if (sd->kavail < needed) {
/*
* Flush data and try another time.
*/
error = ipfw_flush_sopt_data(sd);
if (sd->kavail < needed || error != 0)
return (NULL);
}
addr = sd->kbuf + sd->koff;
sd->koff += needed;
sd->kavail -= needed;
return (addr);
}
caddr_t
ipfw_get_sopt_header(struct sockopt_data *sd, size_t needed)
{
caddr_t addr;
if ((addr = ipfw_get_sopt_space(sd, needed)) == NULL)
return (NULL);
if (sd->kavail > 0)
memset(sd->kbuf + sd->koff, 0, sd->kavail);
return (addr);
}
#define RULE_MAXSIZE (256*sizeof(u_int32_t))

View File

@ -102,17 +102,13 @@ static void free_table_config(struct namedobj_instance *ni,
static void link_table(struct ip_fw_chain *chain, struct table_config *tc);
static void unlink_table(struct ip_fw_chain *chain, struct table_config *tc);
static void free_table_state(void **state, void **xstate, uint8_t type);
static int export_tables(struct ip_fw_chain *ch, ipfw_obj_lheader *olh);
static int export_tables(struct ip_fw_chain *ch, ipfw_obj_lheader *olh,
struct sockopt_data *sd);
static void export_table_info(struct table_config *tc, ipfw_xtable_info *i);
static int dump_table_xentry(void *e, void *arg);
static int check_buffer(size_t items, size_t item_size, size_t header,
size_t bufsize);
static int ipfw_dump_table_v0(struct ip_fw_chain *ch, struct sockopt *sopt,
ip_fw3_opheader *op3, size_t valsize);
static int ipfw_dump_table_v1(struct ip_fw_chain *ch, struct sockopt *sopt,
ip_fw3_opheader *op3, size_t valsize);
static int ipfw_dump_table_v0(struct ip_fw_chain *ch, struct sockopt_data *sd);
static int ipfw_dump_table_v1(struct ip_fw_chain *ch, struct sockopt_data *sd);
static struct table_algo *find_table_algo(struct tables_config *tableconf,
struct tid_info *ti, char *name);
@ -560,24 +556,21 @@ ipfw_lookup_table_extended(struct ip_fw_chain *ch, uint16_t tbl, uint16_t plen,
* Returns 0 on success
*/
int
ipfw_listsize_tables(struct ip_fw_chain *ch, struct sockopt *sopt,
ip_fw3_opheader *op3, size_t valsize)
ipfw_listsize_tables(struct ip_fw_chain *ch, struct sockopt_data *sd)
{
struct _ipfw_obj_lheader *olh;
if (sopt->sopt_valsize < sizeof(*olh))
olh = (struct _ipfw_obj_lheader *)ipfw_get_sopt_header(sd,sizeof(*olh));
if (olh == NULL)
return (EINVAL);
olh = (struct _ipfw_obj_lheader *)op3;
olh->size = sizeof(*olh); /* Make export_table store needed size */
IPFW_UH_RLOCK(ch);
export_tables(ch, olh);
export_tables(ch, olh, sd);
IPFW_UH_RUNLOCK(ch);
sopt->sopt_valsize = sizeof(*olh);
return (sooptcopyout(sopt, olh, sopt->sopt_valsize));
return (0);
}
/*
@ -589,61 +582,32 @@ ipfw_listsize_tables(struct ip_fw_chain *ch, struct sockopt *sopt,
* Returns 0 on success
*/
int
ipfw_list_tables(struct ip_fw_chain *ch, struct sockopt *sopt,
ip_fw3_opheader *op3, size_t valsize)
ipfw_list_tables(struct ip_fw_chain *ch, struct sockopt_data *sd)
{
struct _ipfw_obj_lheader *olh;
uint32_t sz;
int error;
if (sopt->sopt_valsize < sizeof(*olh))
olh = (struct _ipfw_obj_lheader *)ipfw_get_sopt_header(sd,sizeof(*olh));
if (olh == NULL)
return (EINVAL);
olh = (struct _ipfw_obj_lheader *)op3;
if (valsize != olh->size)
return (EINVAL);
/*
* Check if array size is "reasonable":
* Permit valsize between current size and
* 2x current size + 1
*/
IPFW_UH_RLOCK(ch);
sz = ipfw_objhash_count(CHAIN_TO_NI(ch));
IPFW_UH_RUNLOCK(ch);
if (check_buffer(sz, sizeof(ipfw_xtable_info),
sizeof(*olh), valsize) != 0)
return (EINVAL);
olh = malloc(valsize, M_TEMP, M_ZERO | M_WAITOK);
/* Copy header to new storage */
memcpy(olh, op3, sizeof(*olh));
IPFW_UH_RLOCK(ch);
error = export_tables(ch, olh);
IPFW_UH_RUNLOCK(ch);
if (error != 0) {
free(olh, M_TEMP);
return (error);
if (sd->valsize < sz) {
IPFW_UH_RUNLOCK(ch);
return (ENOMEM);
}
/*
* Since we call sooptcopyin() with small buffer,
* sopt_valsize is decreased to reflect supplied
* buffer size. Set it back to original value.
*/
sopt->sopt_valsize = valsize;
error = sooptcopyout(sopt, olh, olh->size);
free(olh, M_TEMP);
error = export_tables(ch, olh, sd);
IPFW_UH_RUNLOCK(ch);
return (0);
return (error);
}
/*
* Store table info to buffer provided by @op3.
* Store table info to buffer provided by @sd.
* Data layout:
* Request: [ ipfw_obj_header ipfw_xtable_info(empty)]
* Reply: [ ipfw_obj_header ipfw_xtable_info ]
@ -651,21 +615,18 @@ ipfw_list_tables(struct ip_fw_chain *ch, struct sockopt *sopt,
* Returns 0 on success.
*/
int
ipfw_describe_table(struct ip_fw_chain *ch, struct sockopt *sopt,
ip_fw3_opheader *op3, size_t valsize)
ipfw_describe_table(struct ip_fw_chain *ch, struct sockopt_data *sd)
{
struct _ipfw_obj_header *oh;
struct table_config *tc;
struct tid_info ti;
size_t sz;
int error;
sz = sizeof(*oh) + sizeof(ipfw_xtable_info);
if (sopt->sopt_valsize < sz)
oh = (struct _ipfw_obj_header *)ipfw_get_sopt_header(sd, sz);
if (oh == NULL)
return (EINVAL);
oh = (struct _ipfw_obj_header *)op3;
objheader_to_ti(oh, &ti);
IPFW_UH_RLOCK(ch);
@ -677,33 +638,31 @@ ipfw_describe_table(struct ip_fw_chain *ch, struct sockopt *sopt,
export_table_info(tc, (ipfw_xtable_info *)(oh + 1));
IPFW_UH_RUNLOCK(ch);
error = sooptcopyout(sopt, oh, sz);
return (error);
return (0);
}
struct dump_args {
struct table_info *ti;
struct table_config *tc;
ipfw_table_entry *ent;
ipfw_table_xentry *xent;
struct sockopt_data *sd;
uint32_t cnt;
uint32_t size;
uint16_t uidx;
ipfw_table_entry *ent;
uint32_t size;
};
int
ipfw_dump_table(struct ip_fw_chain *ch, struct sockopt *sopt,
ip_fw3_opheader *op3, size_t valsize)
ipfw_dump_table(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
struct sockopt_data *sd)
{
int error;
switch (op3->version) {
case 0:
error = ipfw_dump_table_v0(ch, sopt, op3, valsize);
error = ipfw_dump_table_v0(ch, sd);
break;
case 1:
error = ipfw_dump_table_v1(ch, sopt, op3, valsize);
error = ipfw_dump_table_v1(ch, sd);
break;
default:
error = ENOTSUP;
@ -714,15 +673,14 @@ ipfw_dump_table(struct ip_fw_chain *ch, struct sockopt *sopt,
/*
* Dumps all table data
* Data layout (version 1):
* Request: [ ipfw_obj_lheader ], size = ipfw_xtable_info.size
* Reply: [ ipfw_obj_lheader ipfw_xtable_info ipfw_table_xentry x N ]
* Data layout (version 1)(current):
* Request: [ ipfw_obj_header ], size = ipfw_xtable_info.size
* Reply: [ ipfw_obj_header ipfw_xtable_info ipfw_table_xentry x N ]
*
* Returns 0 on success
*/
static int
ipfw_dump_table_v1(struct ip_fw_chain *ch, struct sockopt *sopt,
ip_fw3_opheader *op3, size_t valsize)
ipfw_dump_table_v1(struct ip_fw_chain *ch, struct sockopt_data *sd)
{
struct _ipfw_obj_header *oh;
ipfw_xtable_info *i;
@ -731,13 +689,13 @@ ipfw_dump_table_v1(struct ip_fw_chain *ch, struct sockopt *sopt,
struct table_algo *ta;
struct dump_args da;
uint32_t sz;
int error;
if (sopt->sopt_valsize < sizeof(*oh))
sz = sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info);
oh = (struct _ipfw_obj_header *)ipfw_get_sopt_header(sd, sz);
if (oh == NULL)
return (EINVAL);
oh = (struct _ipfw_obj_header *)op3;
i = (ipfw_xtable_info *)(oh + 1);
objheader_to_ti(oh, &ti);
IPFW_UH_RLOCK(ch);
@ -745,32 +703,19 @@ ipfw_dump_table_v1(struct ip_fw_chain *ch, struct sockopt *sopt,
IPFW_UH_RUNLOCK(ch);
return (ESRCH);
}
sz = tc->count;
IPFW_UH_RUNLOCK(ch);
if (check_buffer(sz, sizeof(ipfw_table_xentry),
sizeof(ipfw_xtable_info) + sizeof(*oh), valsize) != 0)
return (EINVAL);
oh = malloc(valsize, M_TEMP, M_ZERO | M_WAITOK);
i = (ipfw_xtable_info *)(oh + 1);
/* Copy header to new storage */
memcpy(oh, op3, sizeof(*oh));
IPFW_UH_RLOCK(ch);
/* Find table and export info */
if ((tc = find_table(CHAIN_TO_NI(ch), &ti)) == NULL) {
IPFW_UH_RUNLOCK(ch);
free(oh, M_TEMP);
return (ESRCH);
}
export_table_info(tc, i);
if (i->size > valsize) {
sz = tc->count;
if (sd->valsize < sz + tc->count * sizeof(ipfw_table_xentry)) {
/*
* Submitted buffer size is not enough.
* WE've already filled in @i structure with
* relevant table info including size, so we
* can return. Buffer will be flushed automatically.
*/
IPFW_UH_RUNLOCK(ch);
/* XXX: Should we pass size structure back ? */
free(oh, M_TEMP);
return (EINVAL);
return (ENOMEM);
}
/*
@ -779,52 +724,38 @@ ipfw_dump_table_v1(struct ip_fw_chain *ch, struct sockopt *sopt,
memset(&da, 0, sizeof(da));
da.ti = KIDX_TO_TI(ch, tc->no.kidx);
da.tc = tc;
da.xent = (ipfw_table_xentry *)(i + 1);
da.size = (valsize - sizeof(*oh) - sizeof(ipfw_xtable_info)) /
sizeof(ipfw_table_xentry);
da.sd = sd;
ta = tc->ta;
ta->foreach(tc->astate, da.ti, dump_table_xentry, &da);
IPFW_UH_RUNLOCK(ch);
/*
* Since we call sooptcopyin() with small buffer,
* sopt_valsize is decreased to reflect supplied
* buffer size. Set it back to original value.
*/
sopt->sopt_valsize = valsize;
error = sooptcopyout(sopt, oh, i->size);
free(oh, M_TEMP);
return (0);
}
/*
* Dumps all table data
* Data layout (version 0):
* Data layout (version 0)(legacy):
* Request: [ ipfw_xtable ], size = IP_FW_TABLE_XGETSIZE()
* Reply: [ ipfw_xtable ipfw_table_xentry x N ]
*
* Returns 0 on success
*/
static int
ipfw_dump_table_v0(struct ip_fw_chain *ch, struct sockopt *sopt,
ip_fw3_opheader *op3, size_t valsize)
ipfw_dump_table_v0(struct ip_fw_chain *ch, struct sockopt_data *sd)
{
ipfw_xtable *xtbl;
struct tid_info ti;
struct table_config *tc;
struct table_algo *ta;
struct dump_args da;
int error;
size_t sz;
if (valsize < sizeof(ipfw_xtable))
xtbl = (ipfw_xtable *)ipfw_get_sopt_header(sd, sizeof(ipfw_xtable));
if (xtbl == NULL)
return (EINVAL);
xtbl = (ipfw_xtable *)op3;
memset(&ti, 0, sizeof(ti));
ti.set = 0; /* XXX: No way to specify set */
ti.uidx = xtbl->tbl;
@ -834,56 +765,37 @@ ipfw_dump_table_v0(struct ip_fw_chain *ch, struct sockopt *sopt,
IPFW_UH_RUNLOCK(ch);
return (0);
}
sz = tc->count;
IPFW_UH_RUNLOCK(ch);
if (check_buffer(sz, sizeof(ipfw_table_xentry),
sizeof(ipfw_xtable) - sizeof(ipfw_table_xentry), valsize) != 0)
return (EINVAL);
xtbl = malloc(valsize, M_TEMP, M_ZERO | M_WAITOK);
memcpy(xtbl, op3, sizeof(ipfw_xtable));
IPFW_UH_RLOCK(ch);
if ((tc = find_table(CHAIN_TO_NI(ch), &ti)) == NULL) {
IPFW_UH_RUNLOCK(ch);
free(xtbl, M_TEMP);
return (0);
}
/* Check size another time */
sz = tc->count * sizeof(ipfw_table_xentry) + sizeof(ipfw_xtable);
if (sz > valsize) {
xtbl->cnt = tc->count;
xtbl->size = sz;
xtbl->type = tc->no.type;
xtbl->tbl = ti.uidx;
if (sd->valsize < sz) {
/*
* Submitted buffer size is not enough.
* WE've already filled in @i structure with
* relevant table info including size, so we
* can return. Buffer will be flushed automatically.
*/
IPFW_UH_RUNLOCK(ch);
free(xtbl, M_TEMP);
return (EINVAL);
return (ENOMEM);
}
/* Do the actual dump in eXtended format */
memset(&da, 0, sizeof(da));
da.ti = KIDX_TO_TI(ch, tc->no.kidx);
da.tc = tc;
da.xent = &xtbl->xent[0];
da.size = tc->count;
xtbl->type = tc->no.type;
xtbl->tbl = ti.uidx;
da.sd = sd;
ta = tc->ta;
ta->foreach(tc->astate, da.ti, dump_table_xentry, &da);
xtbl->cnt = da.cnt;
xtbl->size = sz;
IPFW_UH_RUNLOCK(ch);
/*
* Since we call sooptcopyin() with small buffer, sopt_valsize is
* decreased to reflect supplied buffer size. Set it back to original value
*/
sopt->sopt_valsize = valsize;
error = sooptcopyout(sopt, xtbl, sz);
free(xtbl, M_TEMP);
return (error);
return (0);
}
/*
@ -925,7 +837,7 @@ ipfw_create_table(struct ip_fw_chain *ch, struct sockopt *sopt,
/*
* Verify user-supplied strings.
* Check for null-terminated/zero-lenght strings/
* Check for null-terminated/zero-length strings/
*/
tname = i->tablename;
aname = i->algoname;
@ -978,26 +890,6 @@ ipfw_create_table(struct ip_fw_chain *ch, struct sockopt *sopt,
return (0);
}
/*
* Checks if supplied buffer size is "reasonable".
* Permit valsize between current needed size and
* 2x needed size + 1
*/
static int
check_buffer(size_t items, size_t item_size, size_t header, size_t bufsize)
{
size_t sz_min, sz_max;
sz_min = items * item_size + header;
sz_max = (2 * items + 1) * item_size + header;
if (bufsize < sz_min || bufsize > sz_max)
return (EINVAL);
return (0);
}
void
objheader_to_ti(struct _ipfw_obj_header *oh, struct tid_info *ti)
{
@ -1029,43 +921,43 @@ static void
export_table_internal(struct namedobj_instance *ni, struct named_object *no,
void *arg)
{
ipfw_obj_lheader *olh;
ipfw_xtable_info *i;
struct sockopt_data *sd;
olh = (ipfw_obj_lheader *)arg;
i = (ipfw_xtable_info *)(caddr_t)(olh + 1) + olh->count;
olh->count++;
sd = (struct sockopt_data *)arg;
i = (ipfw_xtable_info *)ipfw_get_sopt_space(sd, sizeof(*i));
KASSERT(i == 0, ("previously checked buffer is not enough"));
export_table_info((struct table_config *)no, i);
}
/*
* Export all tables as ipfw_xtable_info structures to
* storage provided by @olh.
* storage provided by @sd.
* Returns 0 on success.
*/
static int
export_tables(struct ip_fw_chain *ch, ipfw_obj_lheader *olh)
export_tables(struct ip_fw_chain *ch, ipfw_obj_lheader *olh,
struct sockopt_data *sd)
{
uint32_t size;
uint32_t count;
count = ipfw_objhash_count(CHAIN_TO_NI(ch));
size = count * sizeof(ipfw_xtable_info) + sizeof(ipfw_obj_lheader);
/* Fill in header regadless of buffer size */
olh->count = count;
olh->objsize = sizeof(ipfw_xtable_info);
if (size > olh->size) {
/* Store new values anyway */
olh->count = count;
/* Store necessary size */
olh->size = size;
olh->objsize = sizeof(ipfw_xtable_info);
return (ENOMEM);
}
olh->count = 0;
ipfw_objhash_foreach(CHAIN_TO_NI(ch), export_table_internal, olh);
olh->count = count;
olh->size = size;
olh->objsize = sizeof(ipfw_xtable_info);
ipfw_objhash_foreach(CHAIN_TO_NI(ch), export_table_internal, sd);
return (0);
}
@ -1170,13 +1062,12 @@ dump_table_xentry(void *e, void *arg)
tc = da->tc;
ta = tc->ta;
xent = (ipfw_table_xentry *)ipfw_get_sopt_space(da->sd, sizeof(*xent));
/* Out of memory, returning */
if (da->cnt == da->size)
if (xent == NULL)
return (1);
xent = da->xent++;
xent->len = sizeof(ipfw_table_xentry);
xent->tbl = da->uidx;
da->cnt++;
return (ta->dump_xentry(tc->astate, da->ti, e, xent));
}

View File

@ -91,14 +91,11 @@ void ipfw_table_algo_destroy(struct ip_fw_chain *chain);
/* direct ipfw_ctl handlers */
int ipfw_listsize_tables(struct ip_fw_chain *ch, struct sockopt *sopt,
ip_fw3_opheader *op3, size_t valsize);
int ipfw_list_tables(struct ip_fw_chain *ch, struct sockopt *sopt,
ip_fw3_opheader *op3, size_t valsize);
int ipfw_dump_table(struct ip_fw_chain *ch, struct sockopt *sopt,
ip_fw3_opheader *op3, size_t valsize);
int ipfw_describe_table(struct ip_fw_chain *ch, struct sockopt *sopt,
ip_fw3_opheader *op3, size_t valsize);
int ipfw_listsize_tables(struct ip_fw_chain *ch, struct sockopt_data *sd);
int ipfw_list_tables(struct ip_fw_chain *ch, struct sockopt_data *sd);
int ipfw_dump_table(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
struct sockopt_data *sd);
int ipfw_describe_table(struct ip_fw_chain *ch, struct sockopt_data *sd);
int ipfw_create_table(struct ip_fw_chain *ch, struct sockopt *sopt,
ip_fw3_opheader *op3);