svn commit: r269435 - projects/ipfw/sys/netpfil/ipfw
Alexander V. Chernikov
melifaro at FreeBSD.org
Sat Aug 2 17:18:48 UTC 2014
Author: melifaro
Date: Sat Aug 2 17:18:47 2014
New Revision: 269435
URL: http://svnweb.freebsd.org/changeset/base/269435
Log:
* Fix case when returning more that 4096 bytes of data
* Use different approach to ensure algo has enough space to store N elements:
- explicitly ask algo (under UH_WLOCK) before/after insertion. This (along
with existing reallocation callbacks) really guarantees us that it is safe
to insert N elements at once while holding UH_WLOCK+WLOCK.
- remove old aflags/flags approach
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
projects/ipfw/sys/netpfil/ipfw/ip_fw_table_algo.c
Modified: projects/ipfw/sys/netpfil/ipfw/ip_fw_private.h
==============================================================================
--- projects/ipfw/sys/netpfil/ipfw/ip_fw_private.h Sat Aug 2 16:45:55 2014 (r269434)
+++ projects/ipfw/sys/netpfil/ipfw/ip_fw_private.h Sat Aug 2 17:18:47 2014 (r269435)
@@ -305,6 +305,7 @@ struct sockopt_data {
size_t kavail; /* number of bytes available */
size_t ktotal; /* total bytes pushed */
struct sockopt *sopt; /* socket data */
+ caddr_t sopt_val; /* sopt user buffer */
size_t valsize; /* original data size */
};
Modified: projects/ipfw/sys/netpfil/ipfw/ip_fw_sockopt.c
==============================================================================
--- projects/ipfw/sys/netpfil/ipfw/ip_fw_sockopt.c Sat Aug 2 16:45:55 2014 (r269434)
+++ projects/ipfw/sys/netpfil/ipfw/ip_fw_sockopt.c Sat Aug 2 17:18:47 2014 (r269435)
@@ -1807,6 +1807,7 @@ ipfw_ctl3(struct sockopt *sopt)
}
sdata.sopt = sopt;
+ sdata.sopt_val = sopt->sopt_val;
sdata.valsize = valsize;
/*
@@ -1906,6 +1907,9 @@ ipfw_ctl3(struct sockopt *sopt)
else
ipfw_flush_sopt_data(&sdata);
+ /* Restore original pointer and set number of bytes written */
+ sopt->sopt_val = sdata.sopt_val;
+ sopt->sopt_valsize = sdata.ktotal;
if (sdata.kbuf != xbuf)
free(sdata.kbuf, M_TEMP);
@@ -2113,8 +2117,8 @@ ipfw_ctl(struct sockopt *sopt)
ti.type = IPFW_TABLE_CIDR;
error = (opt == IP_FW_TABLE_ADD) ?
- add_table_entry(chain, &ti, &tei) :
- del_table_entry(chain, &ti, &tei);
+ add_table_entry(chain, &ti, &tei, 1) :
+ del_table_entry(chain, &ti, &tei, 1);
}
break;
@@ -2239,12 +2243,13 @@ static int
ipfw_flush_sopt_data(struct sockopt_data *sd)
{
int error;
+ size_t sz;
- if (sd->koff == 0)
+ if ((sz = sd->koff) == 0)
return (0);
if (sd->sopt->sopt_dir == SOPT_GET) {
- error = sooptcopyout(sd->sopt, sd->kbuf, sd->koff);
+ error = sooptcopyout(sd->sopt, sd->kbuf, sz);
if (error != 0)
return (error);
}
@@ -2257,6 +2262,10 @@ ipfw_flush_sopt_data(struct sockopt_data
else
sd->kavail = sd->valsize - sd->ktotal;
+ /* Update sopt buffer */
+ sd->sopt->sopt_valsize = sd->kavail;
+ sd->sopt->sopt_val = sd->sopt_val + sd->ktotal;
+
return (0);
}
Modified: projects/ipfw/sys/netpfil/ipfw/ip_fw_table.c
==============================================================================
--- projects/ipfw/sys/netpfil/ipfw/ip_fw_table.c Sat Aug 2 16:45:55 2014 (r269434)
+++ projects/ipfw/sys/netpfil/ipfw/ip_fw_table.c Sat Aug 2 17:18:47 2014 (r269435)
@@ -81,7 +81,6 @@ struct table_config {
uint8_t spare;
uint32_t count; /* Number of records */
uint32_t limit; /* Max number of records */
- uint64_t flags; /* state flags */
char tablename[64]; /* table name */
struct table_algo *ta; /* Callbacks for given algo */
void *astate; /* algorithm state */
@@ -121,8 +120,8 @@ static int ipfw_manage_table_ent_v0(stru
static int ipfw_manage_table_ent_v1(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
struct sockopt_data *sd);
-static int modify_table(struct ip_fw_chain *ch, struct table_config *tc,
- struct table_algo *ta, void *ta_buf, uint64_t pflags);
+static int check_table_space(struct ip_fw_chain *ch, struct table_config *tc,
+ struct table_info *ti, uint32_t count);
static int destroy_table(struct ip_fw_chain *ch, struct tid_info *ti);
static struct table_algo *find_table_algo(struct tables_config *tableconf,
@@ -132,10 +131,12 @@ static struct table_algo *find_table_alg
#define CHAIN_TO_NI(chain) (CHAIN_TO_TCFG(chain)->namehash)
#define KIDX_TO_TI(ch, k) (&(((struct table_info *)(ch)->tablestate)[k]))
+#define TA_BUF_SZ 128 /* On-stack buffer for add/delete state */
+
int
add_table_entry(struct ip_fw_chain *ch, struct tid_info *ti,
- struct tentry_info *tei)
+ struct tentry_info *tei, uint32_t count)
{
struct table_config *tc;
struct table_algo *ta;
@@ -143,9 +144,8 @@ add_table_entry(struct ip_fw_chain *ch,
uint16_t kidx;
int error;
uint32_t num;
- uint64_t aflags;
- ipfw_xtable_info xi;
- char ta_buf[128];
+ ipfw_xtable_info *xi;
+ char ta_buf[TA_BUF_SZ];
IPFW_UH_WLOCK(ch);
ni = CHAIN_TO_NI(ch);
@@ -171,7 +171,6 @@ add_table_entry(struct ip_fw_chain *ch,
/* Reference and unlock */
tc->no.refcnt++;
ta = tc->ta;
- aflags = tc->flags;
}
IPFW_UH_WUNLOCK(ch);
@@ -180,10 +179,11 @@ add_table_entry(struct ip_fw_chain *ch,
if ((tei->flags & TEI_FLAGS_COMPAT) == 0)
return (ESRCH);
- memset(&xi, 0, sizeof(xi));
- xi.vtype = IPFW_VTYPE_U32;
+ xi = malloc(sizeof(ipfw_xtable_info), M_TEMP, M_WAITOK|M_ZERO);
+ xi->vtype = IPFW_VTYPE_U32;
- error = create_table_internal(ch, ti, NULL, &xi);
+ error = create_table_internal(ch, ti, NULL, xi);
+ free(xi, M_TEMP);
if (error != 0)
return (error);
@@ -203,22 +203,10 @@ add_table_entry(struct ip_fw_chain *ch,
/* Reference and unlock */
tc->no.refcnt++;
ta = tc->ta;
- aflags = tc->flags;
IPFW_UH_WUNLOCK(ch);
}
- if (aflags != 0) {
-
- /*
- * Previous add/delete call returned non-zero state.
- * Run appropriate handler.
- */
- error = modify_table(ch, tc, ta, &ta_buf, aflags);
- if (error != 0)
- return (error);
- }
-
/* Prepare record (allocate memory) */
memset(&ta_buf, 0, sizeof(ta_buf));
error = ta->prepare_add(ch, tei, &ta_buf);
@@ -227,17 +215,28 @@ add_table_entry(struct ip_fw_chain *ch,
IPFW_UH_WLOCK(ch);
+ /*
+ * Ensure we are able to add all entries without additional
+ * memory allocations. May release/reacquire UH_WLOCK.
+ */
+ kidx = tc->no.kidx;
+ error = check_table_space(ch, tc, KIDX_TO_TI(ch, kidx), count);
+ if (error != 0) {
+ IPFW_UH_WUNLOCK(ch);
+ ta->flush_entry(ch, tei, &ta_buf);
+ return (error);
+ }
+
ni = CHAIN_TO_NI(ch);
/* Drop reference we've used in first search */
tc->no.refcnt--;
- /* Update aflags since it can be changed after previous read */
- aflags = tc->flags;
/* Check limit before adding */
if (tc->limit != 0 && tc->count == tc->limit) {
if ((tei->flags & TEI_FLAGS_UPDATE) == 0) {
IPFW_UH_WUNLOCK(ch);
+ ta->flush_entry(ch, tei, &ta_buf);
return (EFBIG);
}
@@ -256,15 +255,15 @@ add_table_entry(struct ip_fw_chain *ch,
num = 0;
IPFW_WLOCK(ch);
- error = ta->add(tc->astate, KIDX_TO_TI(ch, kidx), tei, &ta_buf,
- &aflags, &num);
+ error = ta->add(tc->astate, KIDX_TO_TI(ch, kidx), tei, &ta_buf, &num);
IPFW_WUNLOCK(ch);
/* Update number of records. */
- if (error == 0)
+ if (error == 0) {
tc->count += num;
-
- tc->flags = aflags;
+ /* Permit post-add algorithm grow/rehash. */
+ error = check_table_space(ch, tc, KIDX_TO_TI(ch, kidx), 0);
+ }
IPFW_UH_WUNLOCK(ch);
@@ -276,7 +275,7 @@ add_table_entry(struct ip_fw_chain *ch,
int
del_table_entry(struct ip_fw_chain *ch, struct tid_info *ti,
- struct tentry_info *tei)
+ struct tentry_info *tei, uint32_t count)
{
struct table_config *tc;
struct table_algo *ta;
@@ -284,8 +283,7 @@ del_table_entry(struct ip_fw_chain *ch,
uint16_t kidx;
int error;
uint32_t num;
- uint64_t aflags;
- char ta_buf[128];
+ char ta_buf[TA_BUF_SZ];
IPFW_UH_WLOCK(ch);
ni = CHAIN_TO_NI(ch);
@@ -299,33 +297,23 @@ del_table_entry(struct ip_fw_chain *ch,
return (EINVAL);
}
- aflags = tc->flags;
ta = tc->ta;
- if (aflags != 0) {
-
- /*
- * Give the chance to algo to shrink its state.
- */
- tc->no.refcnt++;
+ /*
+ * Give a chance for algorithm to shrink.
+ * May release/reacquire UH_WLOCK.
+ */
+ kidx = tc->no.kidx;
+ error = check_table_space(ch, tc, KIDX_TO_TI(ch, kidx), 0);
+ if (error != 0) {
IPFW_UH_WUNLOCK(ch);
- memset(&ta_buf, 0, sizeof(ta_buf));
-
- error = modify_table(ch, tc, ta, &ta_buf, aflags);
-
- IPFW_UH_WLOCK(ch);
- tc->no.refcnt--;
- aflags = tc->flags;
-
- if (error != 0) {
- IPFW_UH_WUNLOCK(ch);
- return (error);
- }
+ ta->flush_entry(ch, tei, &ta_buf);
+ return (error);
}
/*
* We assume ta_buf size is enough for storing
- * prepare_del() key, so we're running under UH_LOCK here.
+ * prepare_del() key, so we're running under UH_WLOCK here.
*/
memset(&ta_buf, 0, sizeof(ta_buf));
if ((error = ta->prepare_del(ch, tei, &ta_buf)) != 0) {
@@ -337,13 +325,14 @@ del_table_entry(struct ip_fw_chain *ch,
num = 0;
IPFW_WLOCK(ch);
- error = ta->del(tc->astate, KIDX_TO_TI(ch, kidx), tei, &ta_buf,
- &aflags, &num);
+ error = ta->del(tc->astate, KIDX_TO_TI(ch, kidx), tei, &ta_buf, &num);
IPFW_WUNLOCK(ch);
- if (error == 0)
+ if (error == 0) {
tc->count -= num;
- tc->flags = aflags;
+ /* Run post-del hook to permit shrinking */
+ error = check_table_space(ch, tc, KIDX_TO_TI(ch, kidx), 0);
+ }
IPFW_UH_WUNLOCK(ch);
@@ -353,49 +342,88 @@ del_table_entry(struct ip_fw_chain *ch,
}
/*
- * Runs callbacks to modify algo state (typically, table resize).
+ * Ensure that table @tc has enough space to add @count entries without
+ * need for reallocation.
*
* Callbacks order:
+ * 0) has_space() (UH_WLOCK) - checks if @count items can be added w/o resize.
+ *
* 1) alloc_modify (no locks, M_WAITOK) - alloc new state based on @pflags.
* 2) prepare_modifyt (UH_WLOCK) - copy old data into new storage
* 3) modify (UH_WLOCK + WLOCK) - switch pointers
- * 4) flush_modify (no locks) - free state, if needed
+ * 4) flush_modify (UH_WLOCK) - free state, if needed
+ *
+ * Returns 0 on success.
*/
static int
-modify_table(struct ip_fw_chain *ch, struct table_config *tc,
- struct table_algo *ta, void *ta_buf, uint64_t pflags)
+check_table_space(struct ip_fw_chain *ch, struct table_config *tc,
+ struct table_info *ti, uint32_t count)
{
- struct table_info *ti;
+ struct table_algo *ta;
+ uint64_t pflags;
+ char ta_buf[TA_BUF_SZ];
int error;
- error = ta->prepare_mod(ta_buf, &pflags);
- if (error != 0)
- return (error);
-
- IPFW_UH_WLOCK(ch);
- ti = KIDX_TO_TI(ch, tc->no.kidx);
+ IPFW_UH_WLOCK_ASSERT(ch);
- error = ta->fill_mod(tc->astate, ti, ta_buf, &pflags);
+ error = 0;
+ ta = tc->ta;
+ /* Acquire reference not to loose @tc between locks/unlocks */
+ tc->no.refcnt++;
/*
- * prepare_mofify may return zero in @pflags to
- * indicate that modifications are not unnesessary.
+ * TODO: think about avoiding race between large add/large delete
+ * operation on algorithm which implements shrinking along with
+ * growing.
*/
+ while (true) {
+ pflags = 0;
+ if (ta->has_space(tc->astate, ti, count, &pflags) != 0) {
+ tc->no.refcnt--;
+ return (0);
+ }
- if (error == 0 && pflags != 0) {
- /* Do actual modification */
- IPFW_WLOCK(ch);
- ta->modify(tc->astate, ti, ta_buf, pflags);
- IPFW_WUNLOCK(ch);
- }
+ /* We have to shrink/grow table */
+ IPFW_UH_WUNLOCK(ch);
+ memset(&ta_buf, 0, sizeof(ta_buf));
+
+ if ((error = ta->prepare_mod(ta_buf, &pflags)) != 0) {
+ IPFW_UH_WLOCK(ch);
+ break;
+ }
- IPFW_UH_WUNLOCK(ch);
+ IPFW_UH_WLOCK(ch);
- ta->flush_mod(ta_buf);
+ /* Check if we still need to alter table */
+ ti = KIDX_TO_TI(ch, tc->no.kidx);
+ if (ta->has_space(tc->astate, ti, count, &pflags) != 0) {
+ /*
+ * Other threads has already performed resize.
+ * Flush our state and return/
+ */
+ ta->flush_mod(ta_buf);
+ break;
+ }
+
+ error = ta->fill_mod(tc->astate, ti, ta_buf, &pflags);
+ if (error == 0) {
+ /* Do actual modification */
+ IPFW_WLOCK(ch);
+ ta->modify(tc->astate, ti, ta_buf, pflags);
+ IPFW_WUNLOCK(ch);
+ }
+
+ /* Anyway, flush data and retry */
+ ta->flush_mod(ta_buf);
+ }
+
+ tc->no.refcnt--;
return (error);
}
+
+
int
ipfw_manage_table_ent(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
struct sockopt_data *sd)
@@ -463,8 +491,8 @@ ipfw_manage_table_ent_v0(struct ip_fw_ch
ti.type = xent->type;
error = (op3->opcode == IP_FW_TABLE_XADD) ?
- add_table_entry(ch, &ti, &tei) :
- del_table_entry(ch, &ti, &tei);
+ add_table_entry(ch, &ti, &tei, 1) :
+ del_table_entry(ch, &ti, &tei, 1);
return (error);
}
@@ -538,8 +566,8 @@ ipfw_manage_table_ent_v1(struct ip_fw_ch
ti.uidx = tent->idx;
error = (oh->opheader.opcode == IP_FW_TABLE_XADD) ?
- add_table_entry(ch, &ti, &tei) :
- del_table_entry(ch, &ti, &tei);
+ add_table_entry(ch, &ti, &tei, 1) :
+ del_table_entry(ch, &ti, &tei, 1);
return (error);
}
@@ -1614,16 +1642,28 @@ find_table_algo(struct tables_config *tc
return (tcfg->def_algo[ti->type]);
}
+/*
+ * Register new table algo @ta.
+ * Stores algo id iside @idx.<F2>
+ *
+ * Returns 0 on success.
+ */
int
ipfw_add_table_algo(struct ip_fw_chain *ch, struct table_algo *ta, size_t size,
int *idx)
{
struct tables_config *tcfg;
struct table_algo *ta_new;
+ size_t sz;
if (size > sizeof(struct table_algo))
return (EINVAL);
+ /* Check for the required on-stack size for add/del */
+ sz = roundup2(ta->ta_buf_size, sizeof(void *));
+ if (sz > TA_BUF_SZ)
+ return (EINVAL);
+
KASSERT(ta->type >= IPFW_TABLE_MAXTYPE,("Increase IPFW_TABLE_MAXTYPE"));
ta_new = malloc(sizeof(struct table_algo), M_IPFW, M_WAITOK | M_ZERO);
@@ -1646,6 +1686,9 @@ ipfw_add_table_algo(struct ip_fw_chain *
return (0);
}
+/*
+ * Unregisters table algo using @idx as id.
+ */
void
ipfw_del_table_algo(struct ip_fw_chain *ch, int idx)
{
@@ -1654,8 +1697,8 @@ ipfw_del_table_algo(struct ip_fw_chain *
tcfg = CHAIN_TO_TCFG(ch);
- KASSERT(idx <= tcfg->algo_count, ("algo idx %d out of rage 1..%d", idx,
- tcfg->algo_count));
+ KASSERT(idx <= tcfg->algo_count, ("algo idx %d out of range 1..%d",
+ idx, tcfg->algo_count));
ta = tcfg->algo[idx];
KASSERT(ta != NULL, ("algo idx %d is NULL", idx));
Modified: projects/ipfw/sys/netpfil/ipfw/ip_fw_table.h
==============================================================================
--- projects/ipfw/sys/netpfil/ipfw/ip_fw_table.h Sat Aug 2 16:45:55 2014 (r269434)
+++ projects/ipfw/sys/netpfil/ipfw/ip_fw_table.h Sat Aug 2 17:18:47 2014 (r269435)
@@ -71,12 +71,14 @@ typedef int (ta_prepare_add)(struct ip_f
typedef int (ta_prepare_del)(struct ip_fw_chain *ch, struct tentry_info *tei,
void *ta_buf);
typedef int (ta_add)(void *ta_state, struct table_info *ti,
- struct tentry_info *tei, void *ta_buf, uint64_t *pflags, uint32_t *pnum);
+ struct tentry_info *tei, void *ta_buf, uint32_t *pnum);
typedef int (ta_del)(void *ta_state, struct table_info *ti,
- struct tentry_info *tei, void *ta_buf, uint64_t *pflags, uint32_t *pnum);
+ struct tentry_info *tei, void *ta_buf, uint32_t *pnum);
typedef void (ta_flush_entry)(struct ip_fw_chain *ch, struct tentry_info *tei,
void *ta_buf);
+typedef int (ta_has_space)(void *ta_state, struct table_info *ti,
+ uint32_t count, uint64_t *pflags);
typedef int (ta_prepare_mod)(void *ta_buf, uint64_t *pflags);
typedef int (ta_fill_mod)(void *ta_state, struct table_info *ti,
void *ta_buf, uint64_t *pflags);
@@ -113,6 +115,7 @@ struct table_algo {
ta_del *del;
ta_flush_entry *flush_entry;
ta_find_tentry *find_tentry;
+ ta_has_space *has_space;
ta_prepare_mod *prepare_mod;
ta_fill_mod *fill_mod;
ta_modify *modify;
@@ -151,9 +154,9 @@ int ipfw_flush_table(struct ip_fw_chain
int ipfw_list_table_algo(struct ip_fw_chain *ch, struct sockopt_data *sd);
/* Exported to support legacy opcodes */
int add_table_entry(struct ip_fw_chain *ch, struct tid_info *ti,
- struct tentry_info *tei);
+ struct tentry_info *tei, uint32_t count);
int del_table_entry(struct ip_fw_chain *ch, struct tid_info *ti,
- struct tentry_info *tei);
+ struct tentry_info *tei, uint32_t count);
int flush_table(struct ip_fw_chain *ch, struct tid_info *ti);
int ipfw_rewrite_table_uidx(struct ip_fw_chain *chain,
Modified: projects/ipfw/sys/netpfil/ipfw/ip_fw_table_algo.c
==============================================================================
--- projects/ipfw/sys/netpfil/ipfw/ip_fw_table_algo.c Sat Aug 2 16:45:55 2014 (r269434)
+++ projects/ipfw/sys/netpfil/ipfw/ip_fw_table_algo.c Sat Aug 2 17:18:47 2014 (r269435)
@@ -397,7 +397,7 @@ ta_prepare_add_cidr(struct ip_fw_chain *
static int
ta_add_cidr(void *ta_state, struct table_info *ti, struct tentry_info *tei,
- void *ta_buf, uint64_t *pflags, uint32_t *pnum)
+ void *ta_buf, uint32_t *pnum)
{
struct radix_node_head *rnh;
struct radix_node *rn;
@@ -489,7 +489,7 @@ ta_prepare_del_cidr(struct ip_fw_chain *
static int
ta_del_cidr(void *ta_state, struct table_info *ti, struct tentry_info *tei,
- void *ta_buf, uint64_t *pflags, uint32_t *pnum)
+ void *ta_buf, uint32_t *pnum)
{
struct radix_node_head *rnh;
struct radix_node *rn;
@@ -526,6 +526,20 @@ ta_flush_cidr_entry(struct ip_fw_chain *
free(tb->ent_ptr, M_IPFW_TBL);
}
+static int
+ta_has_space_radix(void *ta_state, struct table_info *ti, uint32_t count,
+ uint64_t *pflags)
+{
+
+ /*
+ * radix does not not require additional memory allocations
+ * other than nodes itself. Adding new masks to the tree do
+ * but we don't have any API to call (and we don't known which
+ * sizes do we need).
+ */
+ return (1);
+}
+
struct table_algo cidr_radix = {
.name = "cidr:radix",
.type = IPFW_TABLE_CIDR,
@@ -541,6 +555,7 @@ struct table_algo cidr_radix = {
.foreach = ta_foreach_radix,
.dump_tentry = ta_dump_radix_tentry,
.find_tentry = ta_find_radix_tentry,
+ .has_space = ta_has_space_radix,
};
@@ -1115,7 +1130,7 @@ ta_prepare_add_chash(struct ip_fw_chain
static int
ta_add_chash(void *ta_state, struct table_info *ti, struct tentry_info *tei,
- void *ta_buf, uint64_t *pflags, uint32_t *pnum)
+ void *ta_buf, uint32_t *pnum)
{
struct chash_cfg *ccfg;
struct chashbhead *head;
@@ -1172,16 +1187,11 @@ ta_add_chash(void *ta_state, struct tabl
tb->ent_ptr = NULL;
*pnum = 1;
- /* Update counters and check if we need to grow hash */
- if (tei->subtype == AF_INET) {
+ /* Update counters */
+ if (tei->subtype == AF_INET)
ccfg->items4++;
- if (ccfg->items4 > ccfg->size4 && ccfg->size4 < 65536)
- *pflags = (ccfg->size4 * 2) | (1UL << 32);
- } else {
+ else
ccfg->items6++;
- if (ccfg->items6 > ccfg->size6 && ccfg->size6 < 65536)
- *pflags = ccfg->size6 * 2;
- }
}
return (0);
@@ -1200,7 +1210,7 @@ ta_prepare_del_chash(struct ip_fw_chain
static int
ta_del_chash(void *ta_state, struct table_info *ti, struct tentry_info *tei,
- void *ta_buf, uint64_t *pflags, uint32_t *pnum)
+ void *ta_buf, uint32_t *pnum)
{
struct chash_cfg *ccfg;
struct chashbhead *head;
@@ -1263,8 +1273,39 @@ ta_flush_chash_entry(struct ip_fw_chain
struct mod_item {
void *main_ptr;
size_t size;
+ void *main_ptr6;
+ size_t size6;
};
+static int
+ta_has_space_chash(void *ta_state, struct table_info *ti, uint32_t count,
+ uint64_t *pflags)
+{
+ struct chash_cfg *cfg;
+ uint64_t data;
+
+ /*
+ * Since we don't know exact number of IPv4/IPv6 records in @count,
+ * ignore non-zero @count value at all. Check current hash sizes
+ * and return appropriate data.
+ */
+
+ cfg = (struct chash_cfg *)ta_state;
+
+ data = 0;
+ if (cfg->items4 > cfg->size4 && cfg->size4 < 65536)
+ data |= (cfg->size4 * 2) << 16;
+ if (cfg->items6 > cfg->size6 && cfg->size6 < 65536)
+ data |= cfg->size6 * 2;
+
+ if (data != 0) {
+ *pflags = data;
+ return (0);
+ }
+
+ return (1);
+}
+
/*
* Allocate new, larger chash.
*/
@@ -1278,13 +1319,23 @@ ta_prepare_mod_chash(void *ta_buf, uint6
mi = (struct mod_item *)ta_buf;
memset(mi, 0, sizeof(struct mod_item));
- mi->size = *pflags & 0xFFFFFFFF;
- head = malloc(sizeof(struct chashbhead) * mi->size, M_IPFW,
- M_WAITOK | M_ZERO);
- for (i = 0; i < mi->size; i++)
- SLIST_INIT(&head[i]);
-
- mi->main_ptr = head;
+ mi->size = (*pflags >> 16) & 0xFFFF;
+ mi->size6 = *pflags & 0xFFFF;
+ if (mi->size > 0) {
+ head = malloc(sizeof(struct chashbhead) * mi->size,
+ M_IPFW, M_WAITOK | M_ZERO);
+ for (i = 0; i < mi->size; i++)
+ SLIST_INIT(&head[i]);
+ mi->main_ptr = head;
+ }
+
+ if (mi->size6 > 0) {
+ head = malloc(sizeof(struct chashbhead) * mi->size6,
+ M_IPFW, M_WAITOK | M_ZERO);
+ for (i = 0; i < mi->size6; i++)
+ SLIST_INIT(&head[i]);
+ mi->main_ptr6 = head;
+ }
return (0);
}
@@ -1301,7 +1352,6 @@ ta_fill_mod_chash(void *ta_state, struct
return (0);
}
-
/*
* Switch old & new arrays.
*/
@@ -1310,54 +1360,62 @@ ta_modify_chash(void *ta_state, struct t
uint64_t pflags)
{
struct mod_item *mi;
- struct chash_cfg *ccfg;
+ struct chash_cfg *cfg;
struct chashbhead *old_head, *new_head;
struct chashentry *ent, *ent_next;
int af, i, mlen;
uint32_t nhash;
- size_t old_size;
+ size_t old_size, new_size;
mi = (struct mod_item *)ta_buf;
- ccfg = (struct chash_cfg *)ta_state;
+ cfg = (struct chash_cfg *)ta_state;
/* Check which hash we need to grow and do we still need that */
- if ((pflags >> 32) == 1) {
- old_size = ccfg->size4;
+ if (mi->size > 0 && cfg->size4 < mi->size) {
+ new_head = (struct chashbhead *)mi->main_ptr;
+ new_size = mi->size;
+ old_size = cfg->size4;
old_head = ti->state;
- mlen = ccfg->mask4;
+ mlen = cfg->mask4;
af = AF_INET;
- } else {
- old_size = ccfg->size6;
+
+ for (i = 0; i < old_size; i++) {
+ SLIST_FOREACH_SAFE(ent, &old_head[i], next, ent_next) {
+ nhash = hash_ent(ent, af, mlen, new_size);
+ SLIST_INSERT_HEAD(&new_head[nhash], ent, next);
+ }
+ }
+
+ ti->state = new_head;
+ cfg->head4 = new_head;
+ cfg->size4 = mi->size;
+ mi->main_ptr = old_head;
+ }
+
+ if (mi->size6 > 0 && cfg->size6 < mi->size6) {
+ new_head = (struct chashbhead *)mi->main_ptr6;
+ new_size = mi->size6;
+ old_size = cfg->size6;
old_head = ti->xstate;
- mlen = ccfg->mask6;
+ mlen = cfg->mask6;
af = AF_INET6;
- }
- if (old_size >= mi->size)
- return (0);
-
- new_head = (struct chashbhead *)mi->main_ptr;
- for (i = 0; i < old_size; i++) {
- SLIST_FOREACH_SAFE(ent, &old_head[i], next, ent_next) {
- nhash = hash_ent(ent, af, mlen, mi->size);
- SLIST_INSERT_HEAD(&new_head[nhash], ent, next);
+ for (i = 0; i < old_size; i++) {
+ SLIST_FOREACH_SAFE(ent, &old_head[i], next, ent_next) {
+ nhash = hash_ent(ent, af, mlen, new_size);
+ SLIST_INSERT_HEAD(&new_head[nhash], ent, next);
+ }
}
- }
- if (af == AF_INET) {
- ti->state = new_head;
- ccfg->head4 = new_head;
- ccfg->size4 = mi->size;
- } else {
ti->xstate = new_head;
- ccfg->head6 = new_head;
- ccfg->size6 = mi->size;
+ cfg->head6 = new_head;
+ cfg->size6 = mi->size6;
+ mi->main_ptr6 = old_head;
}
- ti->data = (ti->data & 0xFFFFFFFF00000000) | log2(ccfg->size4) << 8 |
- log2(ccfg->size6);
-
- mi->main_ptr = old_head;
+ /* Update lower 32 bits with new values */
+ ti->data &= 0xFFFFFFFF00000000;
+ ti->data |= log2(cfg->size4) << 8 | log2(cfg->size6);
return (0);
}
@@ -1373,6 +1431,8 @@ ta_flush_mod_chash(void *ta_buf)
mi = (struct mod_item *)ta_buf;
if (mi->main_ptr != NULL)
free(mi->main_ptr, M_IPFW);
+ if (mi->main_ptr6 != NULL)
+ free(mi->main_ptr6, M_IPFW);
}
struct table_algo cidr_hash = {
@@ -1390,6 +1450,7 @@ struct table_algo cidr_hash = {
.dump_tentry = ta_dump_chash_tentry,
.find_tentry = ta_find_chash_tentry,
.print_config = ta_print_chash_config,
+ .has_space = ta_has_space_chash,
.prepare_mod = ta_prepare_mod_chash,
.fill_mod = ta_fill_mod_chash,
.modify = ta_modify_chash,
@@ -1678,7 +1739,7 @@ ta_prepare_add_ifidx(struct ip_fw_chain
static int
ta_add_ifidx(void *ta_state, struct table_info *ti, struct tentry_info *tei,
- void *ta_buf, uint64_t *pflags, uint32_t *pnum)
+ void *ta_buf, uint32_t *pnum)
{
struct iftable_cfg *icfg;
struct ifentry *ife, *tmp;
@@ -1726,11 +1787,6 @@ ta_add_ifidx(void *ta_state, struct tabl
ipfw_iface_add_notify(icfg->ch, &ife->ic);
icfg->count++;
- if (icfg->count + 1 == icfg->size) {
- /* Notify core we need to grow */
- *pflags = icfg->size + IFIDX_CHUNK;
- }
-
tb->ife = NULL;
*pnum = 1;
@@ -1764,7 +1820,7 @@ ta_prepare_del_ifidx(struct ip_fw_chain
*/
static int
ta_del_ifidx(void *ta_state, struct table_info *ti, struct tentry_info *tei,
- void *ta_buf, uint64_t *pflags, uint32_t *pnum)
+ void *ta_buf, uint32_t *pnum)
{
struct iftable_cfg *icfg;
struct ifentry *ife;
@@ -1883,6 +1939,22 @@ struct mod_ifidx {
size_t size;
};
+static int
+ta_has_space_ifidx(void *ta_state, struct table_info *ti, uint32_t count,
+ uint64_t *pflags)
+{
+ struct iftable_cfg *cfg;
+
+ cfg = (struct iftable_cfg *)ta_state;
+
+ if (cfg->count + count > cfg->size) {
+ *pflags = roundup2(cfg->count + count, IFIDX_CHUNK);
+ return (0);
+ }
+
+ return (1);
+}
+
/*
* Allocate ned, larger runtime ifidx array.
*/
@@ -2049,6 +2121,7 @@ struct table_algo iface_idx = {
.foreach = ta_foreach_ifidx,
.dump_tentry = ta_dump_ifidx_tentry,
.find_tentry = ta_find_ifidx_tentry,
+ .has_space = ta_has_space_ifidx,
.prepare_mod = ta_prepare_mod_ifidx,
.fill_mod = ta_fill_mod_ifidx,
.modify = ta_modify_ifidx,
@@ -2186,7 +2259,7 @@ ta_prepare_add_numarray(struct ip_fw_cha
static int
ta_add_numarray(void *ta_state, struct table_info *ti, struct tentry_info *tei,
- void *ta_buf, uint64_t *pflags, uint32_t *pnum)
+ void *ta_buf, uint32_t *pnum)
{
struct numarray_cfg *cfg;
struct ta_buf_numarray *tb;
@@ -2219,11 +2292,6 @@ ta_add_numarray(void *ta_state, struct t
KASSERT(res == 1, ("number %d already exists", tb->na.number));
cfg->used++;
ti->data = cfg->used;
-
- if (cfg->used + 1 == cfg->size) {
- /* Notify core we need to grow */
- *pflags = cfg->size + NUMARRAY_CHUNK;
- }
*pnum = 1;
return (0);
@@ -2235,7 +2303,7 @@ ta_add_numarray(void *ta_state, struct t
*/
static int
ta_del_numarray(void *ta_state, struct table_info *ti, struct tentry_info *tei,
- void *ta_buf, uint64_t *pflags, uint32_t *pnum)
+ void *ta_buf, uint32_t *pnum)
{
struct numarray_cfg *cfg;
struct ta_buf_numarray *tb;
@@ -2255,7 +2323,6 @@ ta_del_numarray(void *ta_state, struct t
KASSERT(res == 1, ("number %u does not exist", tb->na.number));
cfg->used--;
ti->data = cfg->used;
-
*pnum = 1;
return (0);
@@ -2274,8 +2341,24 @@ ta_flush_numarray_entry(struct ip_fw_cha
* Table growing callbacks.
*/
+static int
+ta_has_space_numarray(void *ta_state, struct table_info *ti, uint32_t count,
+ uint64_t *pflags)
+{
+ struct numarray_cfg *cfg;
+
+ cfg = (struct numarray_cfg *)ta_state;
+
+ if (cfg->used + count > cfg->size) {
+ *pflags = roundup2(cfg->used + count, NUMARRAY_CHUNK);
+ return (0);
+ }
+
+ return (1);
+}
+
/*
- * Allocate ned, larger runtime numarray array.
+ * Allocate new, larger runtime array.
*/
static int
ta_prepare_mod_numarray(void *ta_buf, uint64_t *pflags)
@@ -2415,6 +2498,7 @@ struct table_algo number_array = {
.foreach = ta_foreach_numarray,
.dump_tentry = ta_dump_numarray_tentry,
.find_tentry = ta_find_numarray_tentry,
+ .has_space = ta_has_space_numarray,
.prepare_mod = ta_prepare_mod_numarray,
.fill_mod = ta_fill_mod_numarray,
.modify = ta_modify_numarray,
@@ -2437,8 +2521,8 @@ struct table_algo number_array = {
*
*
* pflags:
- * [v4=1/v6=0][hsize]
- * [ 32][ 32]
+ * [hsize4][hsize6]
+ * [ 16][ 16]
*/
struct fhashentry;
@@ -2858,7 +2942,7 @@ ta_prepare_add_fhash(struct ip_fw_chain
static int
ta_add_fhash(void *ta_state, struct table_info *ti, struct tentry_info *tei,
- void *ta_buf, uint64_t *pflags, uint32_t *pnum)
+ void *ta_buf, uint32_t *pnum)
{
struct fhash_cfg *cfg;
struct fhashbhead *head;
@@ -2907,8 +2991,6 @@ ta_add_fhash(void *ta_state, struct tabl
/* Update counters and check if we need to grow hash */
cfg->items++;
- if (cfg->items > cfg->size && cfg->size < 65536)
- *pflags = cfg->size * 2;
}
return (0);
@@ -2927,7 +3009,7 @@ ta_prepare_del_fhash(struct ip_fw_chain
static int
ta_del_fhash(void *ta_state, struct table_info *ti, struct tentry_info *tei,
- void *ta_buf, uint64_t *pflags, uint32_t *pnum)
+ void *ta_buf, uint32_t *pnum)
{
struct fhash_cfg *cfg;
struct fhashbhead *head;
@@ -2977,6 +3059,22 @@ ta_flush_fhash_entry(struct ip_fw_chain
* Hash growing callbacks.
*/
+static int
+ta_has_space_fhash(void *ta_state, struct table_info *ti, uint32_t count,
+ uint64_t *pflags)
+{
+ struct fhash_cfg *cfg;
+
+ cfg = (struct fhash_cfg *)ta_state;
+
+ if (cfg->items > cfg->size && cfg->size < 65536) {
+ *pflags = cfg->size * 2;
+ return (0);
+ }
+
+ return (1);
+}
+
/*
* Allocate new, larger fhash.
*/
@@ -3085,6 +3183,7 @@ struct table_algo flow_hash = {
.foreach = ta_foreach_fhash,
.dump_tentry = ta_dump_fhash_tentry,
.find_tentry = ta_find_fhash_tentry,
+ .has_space = ta_has_space_fhash,
.prepare_mod = ta_prepare_mod_fhash,
.fill_mod = ta_fill_mod_fhash,
.modify = ta_modify_fhash,
More information about the svn-src-projects
mailing list