svn commit: r267954 - projects/ipfw/sys/netpfil/ipfw
Alexander V. Chernikov
melifaro at FreeBSD.org
Fri Jun 27 10:07:01 UTC 2014
Author: melifaro
Date: Fri Jun 27 10:07:00 2014
New Revision: 267954
URL: http://svnweb.freebsd.org/changeset/base/267954
Log:
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.
Modified:
projects/ipfw/sys/netpfil/ipfw/ip_fw_private.h
projects/ipfw/sys/netpfil/ipfw/ip_fw_sockopt.c
projects/ipfw/sys/netpfil/ipfw/ip_fw_table.c
projects/ipfw/sys/netpfil/ipfw/ip_fw_table.h
Modified: projects/ipfw/sys/netpfil/ipfw/ip_fw_private.h
==============================================================================
--- projects/ipfw/sys/netpfil/ipfw/ip_fw_private.h Fri Jun 27 09:11:24 2014 (r267953)
+++ projects/ipfw/sys/netpfil/ipfw/ip_fw_private.h Fri Jun 27 10:07:00 2014 (r267954)
@@ -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 {
Modified: projects/ipfw/sys/netpfil/ipfw/ip_fw_sockopt.c
==============================================================================
--- projects/ipfw/sys/netpfil/ipfw/ip_fw_sockopt.c Fri Jun 27 09:11:24 2014 (r267953)
+++ projects/ipfw/sys/netpfil/ipfw/ip_fw_sockopt.c Fri Jun 27 10:07:00 2014 (r267954)
@@ -88,6 +88,7 @@ static uint32_t objhash_hash_name(struct
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,
#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))
Modified: projects/ipfw/sys/netpfil/ipfw/ip_fw_table.c
==============================================================================
--- projects/ipfw/sys/netpfil/ipfw/ip_fw_table.c Fri Jun 27 09:11:24 2014 (r267953)
+++ projects/ipfw/sys/netpfil/ipfw/ip_fw_table.c Fri Jun 27 10:07:00 2014 (r267954)
@@ -102,17 +102,13 @@ static void free_table_config(struct nam
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_
* 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
* 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,
* 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 *
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,
/*
* 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 *c
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 *c
IPFW_UH_RUNLOCK(ch);
return (ESRCH);
}
+ export_table_info(tc, i);
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);
+ if (sd->valsize < sz + tc->count * sizeof(ipfw_table_xentry)) {
- 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) {
+ /*
+ * 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 *c
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 *c
IPFW_UH_RUNLOCK(ch);
return (0);
}
- sz = tc->count;
- IPFW_UH_RUNLOCK(ch);
+ sz = tc->count * sizeof(ipfw_table_xentry) + sizeof(ipfw_xtable);
- if (check_buffer(sz, sizeof(ipfw_table_xentry),
- sizeof(ipfw_xtable) - sizeof(ipfw_table_xentry), valsize) != 0)
- return (EINVAL);
+ xtbl->cnt = tc->count;
+ xtbl->size = sz;
+ xtbl->type = tc->no.type;
+ xtbl->tbl = ti.uidx;
- xtbl = malloc(valsize, M_TEMP, M_ZERO | M_WAITOK);
- memcpy(xtbl, op3, sizeof(ipfw_xtable));
+ if (sd->valsize < sz) {
- 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) {
+ /*
+ * 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
/*
* 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
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));
}
Modified: projects/ipfw/sys/netpfil/ipfw/ip_fw_table.h
==============================================================================
--- projects/ipfw/sys/netpfil/ipfw/ip_fw_table.h Fri Jun 27 09:11:24 2014 (r267953)
+++ projects/ipfw/sys/netpfil/ipfw/ip_fw_table.h Fri Jun 27 10:07:00 2014 (r267954)
@@ -91,14 +91,11 @@ void ipfw_table_algo_destroy(struct ip_f
/* 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);
More information about the svn-src-projects
mailing list