* Make objhash api a bit more abstract by providing ability to specify

own hash/compare functions.
* Add requirement for table algorithms to copy "valie" field in @add
  callback instead of "prepare_add".
* Document existing requirement for table algorithms to store value
  of deleted record to @tei.
This commit is contained in:
Alexander V. Chernikov 2014-08-30 17:18:11 +00:00
parent 832fd78087
commit 1326363253
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/projects/ipfw/; revision=270846
3 changed files with 69 additions and 24 deletions

View File

@ -267,7 +267,7 @@ struct ip_fw_chain {
uint32_t id; /* ruleset id */
int n_rules; /* number of static rules */
LIST_HEAD(nat_list, cfg_nat) nat; /* list of nat entries */
void *tablestate; /* runtime table info */
void *tablestate; /* runtime table info */
int *idxmap; /* skipto array of rules */
#if defined( __linux__ ) || defined( _WIN32 )
spinlock_t rwmtx;
@ -519,6 +519,9 @@ caddr_t ipfw_get_sopt_header(struct sockopt_data *sd, size_t needed);
typedef void (objhash_cb_t)(struct namedobj_instance *ni, struct named_object *,
void *arg);
typedef uint32_t (objhash_hash_f)(struct namedobj_instance *ni, void *key,
uint32_t kopt);
typedef int (objhash_cmp_f)(struct named_object *no, void *key, uint32_t kopt);
struct namedobj_instance *ipfw_objhash_create(uint32_t items);
void ipfw_objhash_destroy(struct namedobj_instance *);
void ipfw_objhash_bitmap_alloc(uint32_t items, void **idx, int *pblocks);
@ -527,6 +530,7 @@ void ipfw_objhash_bitmap_merge(struct namedobj_instance *ni,
void ipfw_objhash_bitmap_swap(struct namedobj_instance *ni,
void **idx, int *blocks);
void ipfw_objhash_bitmap_free(void *idx, int blocks);
void ipfw_objhash_set_hashf(struct namedobj_instance *ni, objhash_hash_f *f);
struct named_object *ipfw_objhash_lookup_name(struct namedobj_instance *ni,
uint32_t set, char *name);
struct named_object *ipfw_objhash_lookup_kidx(struct namedobj_instance *ni,
@ -540,6 +544,8 @@ void ipfw_objhash_foreach(struct namedobj_instance *ni, objhash_cb_t *f,
void *arg);
int ipfw_objhash_free_idx(struct namedobj_instance *ni, uint16_t idx);
int ipfw_objhash_alloc_idx(void *n, uint16_t *pidx);
void ipfw_objhash_set_funcs(struct namedobj_instance *ni,
objhash_hash_f *hash_f, objhash_cmp_f *cmp_f);
/* In ip_fw_table.c */
struct table_info;

View File

@ -88,12 +88,15 @@ struct namedobj_instance {
uint32_t max_blocks; /* number of "long" blocks in bitmask */
uint32_t count; /* number of items */
uint16_t free_off[IPFW_MAX_SETS]; /* first possible free offset */
objhash_hash_f *hash_f;
objhash_cmp_f *cmp_f;
};
#define BLOCK_ITEMS (8 * sizeof(u_long)) /* Number of items for ffsl() */
static uint32_t objhash_hash_name(struct namedobj_instance *ni, uint32_t set,
char *name);
static uint32_t objhash_hash_val(struct namedobj_instance *ni, uint32_t val);
static uint32_t objhash_hash_name(struct namedobj_instance *ni, void *key,
uint32_t kopt);
static uint32_t objhash_hash_idx(struct namedobj_instance *ni, uint32_t val);
static int objhash_cmp_name(struct named_object *no, void *name, uint32_t set);
static int ipfw_flush_sopt_data(struct sockopt_data *sd);
@ -3078,6 +3081,10 @@ ipfw_objhash_create(uint32_t items)
for (i = 0; i < ni->nv_size; i++)
TAILQ_INIT(&ni->values[i]);
/* Set default hashing/comparison functions */
ni->hash_f = objhash_hash_name;
ni->cmp_f = objhash_cmp_name;
/* Allocate bitmask separately due to possible resize */
ipfw_objhash_bitmap_alloc(items, (void*)&ni->idx_mask, &ni->max_blocks);
@ -3092,18 +3099,37 @@ ipfw_objhash_destroy(struct namedobj_instance *ni)
free(ni, M_IPFW);
}
void
ipfw_objhash_set_funcs(struct namedobj_instance *ni, objhash_hash_f *hash_f,
objhash_cmp_f *cmp_f)
{
ni->hash_f = hash_f;
ni->cmp_f = cmp_f;
}
static uint32_t
objhash_hash_name(struct namedobj_instance *ni, uint32_t set, char *name)
objhash_hash_name(struct namedobj_instance *ni, void *name, uint32_t set)
{
uint32_t v;
v = fnv_32_str(name, FNV1_32_INIT);
v = fnv_32_str((char *)name, FNV1_32_INIT);
return (v % ni->nn_size);
}
static int
objhash_cmp_name(struct named_object *no, void *name, uint32_t set)
{
if ((strcmp(no->name, (char *)name) == 0) && (no->set == set))
return (0);
return (1);
}
static uint32_t
objhash_hash_val(struct namedobj_instance *ni, uint32_t val)
objhash_hash_idx(struct namedobj_instance *ni, uint32_t val)
{
uint32_t v;
@ -3118,10 +3144,10 @@ ipfw_objhash_lookup_name(struct namedobj_instance *ni, uint32_t set, char *name)
struct named_object *no;
uint32_t hash;
hash = objhash_hash_name(ni, set, name);
hash = ni->hash_f(ni, name, set);
TAILQ_FOREACH(no, &ni->names[hash], nn_next) {
if ((strcmp(no->name, name) == 0) && (no->set == set))
if (ni->cmp_f(no, name, set) == 0)
return (no);
}
@ -3134,7 +3160,7 @@ ipfw_objhash_lookup_kidx(struct namedobj_instance *ni, uint16_t kidx)
struct named_object *no;
uint32_t hash;
hash = objhash_hash_val(ni, kidx);
hash = objhash_hash_idx(ni, kidx);
TAILQ_FOREACH(no, &ni->values[hash], nv_next) {
if (no->kidx == kidx)
@ -3160,10 +3186,10 @@ ipfw_objhash_add(struct namedobj_instance *ni, struct named_object *no)
{
uint32_t hash;
hash = objhash_hash_name(ni, no->set, no->name);
hash = ni->hash_f(ni, no->name, no->set);
TAILQ_INSERT_HEAD(&ni->names[hash], no, nn_next);
hash = objhash_hash_val(ni, no->kidx);
hash = objhash_hash_idx(ni, no->kidx);
TAILQ_INSERT_HEAD(&ni->values[hash], no, nv_next);
ni->count++;
@ -3174,10 +3200,10 @@ ipfw_objhash_del(struct namedobj_instance *ni, struct named_object *no)
{
uint32_t hash;
hash = objhash_hash_name(ni, no->set, no->name);
hash = ni->hash_f(ni, no->name, no->set);
TAILQ_REMOVE(&ni->names[hash], no, nn_next);
hash = objhash_hash_val(ni, no->kidx);
hash = objhash_hash_idx(ni, no->kidx);
TAILQ_REMOVE(&ni->values[hash], no, nv_next);
ni->count--;
@ -3238,7 +3264,7 @@ ipfw_objhash_free_idx(struct namedobj_instance *ni, uint16_t idx)
}
/*
* Allocate new index in given set and stores in in @pidx.
* Allocate new index in given instance and stores in in @pidx.
* Returns 0 on success.
*/
int

View File

@ -106,6 +106,9 @@ __FBSDID("$FreeBSD: projects/ipfw/sys/netpfil/ipfw/ip_fw_table.c 267384 2014-06-
* void *ta_buf);
* MANDATORY, unlocked. (M_WAITOK). Returns 0 on success.
*
* Allocates state and fills it in with all necessary data (EXCEPT value)
* from @tei to minimize operations needed to be done under WLOCK.
* "value" field has to be copied to new entry in @add callback.
* Buffer ta_buf of size ta->ta_buf_sz may be used to store
* allocated state.
*
@ -132,6 +135,7 @@ __FBSDID("$FreeBSD: projects/ipfw/sys/netpfil/ipfw/ip_fw_table.c 267384 2014-06-
* TEI_FLAGS_UPDATE: request to add or update entry.
* TEI_FLAGS_DONTADD: request to update (but not add) entry.
* * Caller is required to do the following:
* copy real entry value from @tei
* entry added: return 0, set 1 to @pnum
* entry updated: return 0, store 0 to @pnum, store old value in @tei,
* add TEI_FLAGS_UPDATED flag to @tei.
@ -148,7 +152,7 @@ __FBSDID("$FreeBSD: projects/ipfw/sys/netpfil/ipfw/ip_fw_table.c 267384 2014-06-
*
* Delete entry using previously set up in @ta_buf.
* * Caller is required to do the following:
* entry deleted: return 0, set 1 to @pnum
* entry deleted: return 0, set 1 to @pnum, store old value in @tei.
* entry not found: return ENOENT
* other error: return non-zero error code.
*
@ -620,7 +624,6 @@ ta_prepare_add_radix(struct ip_fw_chain *ch, struct tentry_info *tei,
if (mlen > 32)
return (EINVAL);
ent = malloc(sizeof(*ent), M_IPFW_TBL, M_WAITOK | M_ZERO);
ent->value = tei->value;
ent->masklen = mlen;
addr = (struct sockaddr *)&ent->addr;
@ -633,7 +636,6 @@ ta_prepare_add_radix(struct ip_fw_chain *ch, struct tentry_info *tei,
if (mlen > 128)
return (EINVAL);
xent = malloc(sizeof(*xent), M_IPFW_TBL, M_WAITOK | M_ZERO);
xent->value = tei->value;
xent->masklen = mlen;
addr = (struct sockaddr *)&xent->addr6;
@ -667,10 +669,14 @@ ta_add_radix(void *ta_state, struct table_info *ti, struct tentry_info *tei,
cfg = (struct radix_cfg *)ta_state;
tb = (struct ta_buf_radix *)ta_buf;
if (tei->subtype == AF_INET)
/* Save current entry value from @tei */
if (tei->subtype == AF_INET) {
rnh = ti->state;
else
((struct radix_addr_entry *)tb->ent_ptr)->value = tei->value;
} else {
rnh = ti->xstate;
((struct radix_addr_xentry *)tb->ent_ptr)->value = tei->value;
}
/* Search for an entry first */
rn = rnh->rnh_lookup(tb->addr_ptr, tb->mask_ptr, rnh);
@ -1320,7 +1326,6 @@ tei_to_chash_ent(struct tentry_info *tei, struct chashentry *ent)
/* Unknown CIDR type */
return (EINVAL);
}
ent->value = tei->value;
return (0);
}
@ -1439,6 +1444,10 @@ ta_add_chash(void *ta_state, struct table_info *ti, struct tentry_info *tei,
hash = 0;
exists = 0;
/* Read current value from @tei */
ent->value = tei->value;
/* Read cuurrent value */
if (tei->subtype == AF_INET) {
if (tei->masklen != cfg->mask4)
return (EINVAL);
@ -2030,7 +2039,6 @@ ta_prepare_add_ifidx(struct ip_fw_chain *ch, struct tentry_info *tei,
return (EINVAL);
ife = malloc(sizeof(struct ifentry), M_IPFW_TBL, M_WAITOK | M_ZERO);
ife->value = tei->value;
ife->ic.cb = if_notifier;
ife->ic.cbdata = ife;
@ -2063,6 +2071,7 @@ ta_add_ifidx(void *ta_state, struct table_info *ti, struct tentry_info *tei,
ife = tb->ife;
ife->icfg = icfg;
ife->value = tei->value;
tmp = (struct ifentry *)ipfw_objhash_lookup_name(icfg->ii, 0, ifname);
@ -2577,7 +2586,6 @@ ta_prepare_add_numarray(struct ip_fw_chain *ch, struct tentry_info *tei,
tb = (struct ta_buf_numarray *)ta_buf;
tb->na.number = *((uint32_t *)tei->paddr);
tb->na.value = tei->value;
return (0);
}
@ -2595,6 +2603,9 @@ ta_add_numarray(void *ta_state, struct table_info *ti, struct tentry_info *tei,
tb = (struct ta_buf_numarray *)ta_buf;
cfg = (struct numarray_cfg *)ta_state;
/* Read current value from @tei */
tb->na.value = tei->value;
ri = numarray_find(ti, &tb->na.number);
if (ri != NULL) {
@ -3155,7 +3166,6 @@ tei_to_fhash_ent(struct tentry_info *tei, struct fhashentry *ent)
ent->af = tei->subtype;
ent->proto = tfe->proto;
ent->value = tei->value;
ent->dport = ntohs(tfe->dport);
ent->sport = ntohs(tfe->sport);
@ -3287,6 +3297,9 @@ ta_add_fhash(void *ta_state, struct table_info *ti, struct tentry_info *tei,
ent = (struct fhashentry *)tb->ent_ptr;
exists = 0;
/* Read current value from @tei */
ent->value = tei->value;
head = cfg->head;
hash = hash_flow_ent(ent, cfg->size);