Date: Fri, 27 Jun 2014 10:07:00 +0000 (UTC) From: "Alexander V. Chernikov" <melifaro@FreeBSD.org> To: src-committers@freebsd.org, svn-src-projects@freebsd.org Subject: svn commit: r267954 - projects/ipfw/sys/netpfil/ipfw Message-ID: <201406271007.s5RA70Yc087506@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
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);
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201406271007.s5RA70Yc087506>