* Require explicit table creation before use on kernel side.
* Add resize callbacks for upcoming table-based algorithms. Kernel changes: * s/ipfw_modify_table/ipfw_manage_table_ent/ * Simplify add_table_entry(): make table creation a separate piece of code. Do not perform creation if not in "compat" mode. * Add ability to perform modification of algorithm state (like table resize). The following callbacks were added: - prepare_mod (allocate new state, without locks) - fill_mod (UH_WLOCK, copy old state to new one) - modify (UH_WLOCK + WLOCK, switch state) - flush_mod (no locks, flushes allocated data) Given callbacks are called if table modification has been requested by add or delete callbacks. Additional u64 tc->'flags' field was added to pass these requests. * Change add/del table ent format: permit adding/removing multiple entries at once (only 1 supported at the moment). Userland changes: * Auto-create tables with warning
This commit is contained in:
parent
e0a8b9ee29
commit
db785d3199
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/projects/ipfw/; revision=269121
@ -465,7 +465,8 @@ static int
|
||||
table_do_modify_record(int cmd, ipfw_obj_header *oh,
|
||||
ipfw_obj_tentry *tent, int update)
|
||||
{
|
||||
char xbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_obj_tentry)];
|
||||
ipfw_obj_ctlv *ctlv;
|
||||
char xbuf[sizeof(*oh) + sizeof(ipfw_obj_ctlv) + sizeof(*tent)];
|
||||
int error;
|
||||
|
||||
memset(xbuf, 0, sizeof(xbuf));
|
||||
@ -473,8 +474,12 @@ table_do_modify_record(int cmd, ipfw_obj_header *oh,
|
||||
oh = (ipfw_obj_header *)xbuf;
|
||||
oh->opheader.version = 1;
|
||||
|
||||
memcpy(oh + 1, tent, sizeof(*tent));
|
||||
tent = (ipfw_obj_tentry *)(oh + 1);
|
||||
ctlv = (ipfw_obj_ctlv *)(oh + 1);
|
||||
ctlv->count = 1;
|
||||
ctlv->head.length = sizeof(*ctlv) + sizeof(*tent);
|
||||
|
||||
memcpy(ctlv + 1, tent, sizeof(*tent));
|
||||
tent = (ipfw_obj_tentry *)(ctlv + 1);
|
||||
if (update != 0)
|
||||
tent->head.flags |= IPFW_TF_UPDATE;
|
||||
tent->head.length = sizeof(ipfw_obj_tentry);
|
||||
@ -501,6 +506,19 @@ table_modify_record(ipfw_obj_header *oh, int ac, char *av[], int add, int update
|
||||
tent.idx = 1;
|
||||
|
||||
tentry_fill_key(oh, &tent, *av, &type, &vtype, &xi);
|
||||
|
||||
/*
|
||||
* compability layer: auto-create table if not exists
|
||||
*/
|
||||
if (xi.tablename[0] == '\0') {
|
||||
xi.type = type;
|
||||
xi.vtype = vtype;
|
||||
strlcpy(xi.tablename, oh->ntlv.name, sizeof(xi.tablename));
|
||||
fprintf(stderr, "DEPRECATED: inserting data info non-existent "
|
||||
"table %s. (auto-created)\n", xi.tablename);
|
||||
table_do_create(oh, &xi);
|
||||
}
|
||||
|
||||
oh->ntlv.type = type;
|
||||
ac--; av++;
|
||||
|
||||
@ -659,6 +677,7 @@ tentry_fill_key(ipfw_obj_header *oh, ipfw_obj_tentry *tent, char *key,
|
||||
{
|
||||
uint8_t type, vtype;
|
||||
int error;
|
||||
char *del;
|
||||
|
||||
type = 0;
|
||||
vtype = 0;
|
||||
@ -678,6 +697,8 @@ tentry_fill_key(ipfw_obj_header *oh, ipfw_obj_tentry *tent, char *key,
|
||||
* Compability layer: try to interpret data as CIDR
|
||||
* before failing.
|
||||
*/
|
||||
if ((del = strchr(key, '/')) != NULL)
|
||||
*del = '\0';
|
||||
if (inet_pton(AF_INET, key, &tent->k.addr6) == 1 ||
|
||||
inet_pton(AF_INET6, key, &tent->k.addr6) == 1) {
|
||||
/* OK Prepare and send */
|
||||
@ -690,8 +711,10 @@ tentry_fill_key(ipfw_obj_header *oh, ipfw_obj_tentry *tent, char *key,
|
||||
} else {
|
||||
/* Inknown key */
|
||||
errx(EX_USAGE, "Table %s does not exist, cannot guess "
|
||||
"key type", oh->ntlv.name);
|
||||
"key '%s' type", oh->ntlv.name, key);
|
||||
}
|
||||
if (del != NULL)
|
||||
*del = '/';
|
||||
}
|
||||
|
||||
tentry_fill_key_type(key, tent, type);
|
||||
|
@ -1992,7 +1992,7 @@ ipfw_ctl(struct sockopt *sopt)
|
||||
|
||||
case IP_FW_TABLE_XADD: /* IP_FW3 */
|
||||
case IP_FW_TABLE_XDEL: /* IP_FW3 */
|
||||
error = ipfw_modify_table(chain, op3, &sdata);
|
||||
error = ipfw_manage_table_ent(chain, op3, &sdata);
|
||||
break;
|
||||
case IP_FW_TABLE_XFIND: /* IP_FW3 */
|
||||
error = ipfw_find_table_entry(chain, op3, &sdata);
|
||||
|
@ -77,14 +77,14 @@ struct table_config {
|
||||
struct named_object no;
|
||||
uint8_t vtype; /* format table type */
|
||||
uint8_t linked; /* 1 if already linked */
|
||||
uint16_t spare0;
|
||||
uint16_t spare;
|
||||
uint32_t count; /* 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 */
|
||||
struct table_info ti; /* data to put to table_info */
|
||||
};
|
||||
#define TABLE_SET(set) ((V_fw_tables_sets != 0) ? set : 0)
|
||||
|
||||
struct tables_config {
|
||||
struct namedobj_instance *namehash;
|
||||
@ -95,9 +95,11 @@ struct tables_config {
|
||||
static struct table_config *find_table(struct namedobj_instance *ni,
|
||||
struct tid_info *ti);
|
||||
static struct table_config *alloc_table_config(struct namedobj_instance *ni,
|
||||
struct tid_info *ti, struct table_algo *ta, char *adata);
|
||||
struct tid_info *ti, struct table_algo *ta, char *adata, uint8_t vtype);
|
||||
static void free_table_config(struct namedobj_instance *ni,
|
||||
struct table_config *tc);
|
||||
static int create_table_internal(struct ip_fw_chain *ch, struct tid_info *ti,
|
||||
char *aname, uint8_t vtype);
|
||||
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);
|
||||
@ -110,11 +112,13 @@ static int dump_table_xentry(void *e, void *arg);
|
||||
|
||||
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 int ipfw_modify_table_v0(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
|
||||
static int ipfw_manage_table_ent_v0(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
|
||||
struct sockopt_data *sd);
|
||||
static int ipfw_modify_table_v1(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
|
||||
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 destroy_table(struct ip_fw_chain *ch, struct tid_info *ti);
|
||||
|
||||
static struct table_algo *find_table_algo(struct tables_config *tableconf,
|
||||
@ -130,11 +134,12 @@ int
|
||||
add_table_entry(struct ip_fw_chain *ch, struct tid_info *ti,
|
||||
struct tentry_info *tei)
|
||||
{
|
||||
struct table_config *tc, *tc_new;
|
||||
struct table_config *tc;
|
||||
struct table_algo *ta;
|
||||
struct namedobj_instance *ni;
|
||||
uint16_t kidx;
|
||||
int error;
|
||||
uint64_t aflags;
|
||||
char ta_buf[128];
|
||||
|
||||
IPFW_UH_WLOCK(ch);
|
||||
@ -154,72 +159,65 @@ add_table_entry(struct ip_fw_chain *ch, struct tid_info *ti,
|
||||
/* Reference and unlock */
|
||||
tc->no.refcnt++;
|
||||
ta = tc->ta;
|
||||
aflags = tc->flags;
|
||||
}
|
||||
IPFW_UH_WUNLOCK(ch);
|
||||
|
||||
tc_new = NULL;
|
||||
if (tc == NULL) {
|
||||
/* Table not found. We have to create new one */
|
||||
if ((ta = find_table_algo(CHAIN_TO_TCFG(ch), ti, NULL)) == NULL)
|
||||
return (ENOTSUP);
|
||||
/* Compability mode: create new table for old clients */
|
||||
if ((tei->flags & TEI_FLAGS_COMPAT) == 0)
|
||||
return (ESRCH);
|
||||
|
||||
tc_new = alloc_table_config(ni, ti, ta, NULL);
|
||||
if (tc_new == NULL)
|
||||
return (ENOMEM);
|
||||
error = create_table_internal(ch, ti, NULL, IPFW_VTYPE_U32);
|
||||
|
||||
if (error != 0)
|
||||
return (error);
|
||||
|
||||
/* Let's try to find & reference another time */
|
||||
IPFW_UH_WLOCK(ch);
|
||||
if ((tc = find_table(ni, ti)) == NULL) {
|
||||
IPFW_UH_WUNLOCK(ch);
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
if (tc->no.type != ti->type) {
|
||||
IPFW_UH_WUNLOCK(ch);
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
/* 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(tei, &ta_buf);
|
||||
if (error != 0) {
|
||||
if (tc_new != NULL)
|
||||
free_table_config(ni, tc_new);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
}
|
||||
|
||||
IPFW_UH_WLOCK(ch);
|
||||
|
||||
ni = CHAIN_TO_NI(ch);
|
||||
|
||||
if (tc == NULL) {
|
||||
/* Check if another table has been allocated by other thread */
|
||||
if ((tc = find_table(ni, ti)) != NULL) {
|
||||
|
||||
/*
|
||||
* Check if algoritm is the same since we've
|
||||
* already allocated state using @ta algoritm
|
||||
* callbacks.
|
||||
*/
|
||||
if (tc->ta != ta) {
|
||||
IPFW_UH_WUNLOCK(ch);
|
||||
error = EINVAL;
|
||||
goto done;
|
||||
}
|
||||
} else {
|
||||
/* Table still does not exists */
|
||||
|
||||
/* Allocate table index. */
|
||||
if (ipfw_objhash_alloc_idx(ni, &kidx) != 0) {
|
||||
/* Index full. */
|
||||
IPFW_UH_WUNLOCK(ch);
|
||||
printf("Unable to allocate index for table %s"
|
||||
"in set %u. Consider increasing "
|
||||
"net.inet.ip.fw.tables_max",
|
||||
tc_new->no.name, ti->set);
|
||||
error = EBUSY;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Set tc_new to zero not to free it afterwards. */
|
||||
tc = tc_new;
|
||||
tc_new = NULL;
|
||||
/* Save kidx */
|
||||
tc->no.kidx = kidx;
|
||||
}
|
||||
} else {
|
||||
/* Drop reference we've used in first search */
|
||||
tc->no.refcnt--;
|
||||
}
|
||||
/* Update aflags since it can be changed after previous read */
|
||||
aflags = tc->flags;
|
||||
|
||||
/* We've got valid table in @tc. Let's add data */
|
||||
kidx = tc->no.kidx;
|
||||
@ -227,10 +225,7 @@ add_table_entry(struct ip_fw_chain *ch, struct tid_info *ti,
|
||||
|
||||
IPFW_WLOCK(ch);
|
||||
|
||||
if (tc->linked == 0)
|
||||
link_table(ch, tc);
|
||||
|
||||
error = ta->add(tc->astate, KIDX_TO_TI(ch, kidx), tei, &ta_buf);
|
||||
error = ta->add(tc->astate, KIDX_TO_TI(ch, kidx), tei, &ta_buf, &aflags);
|
||||
|
||||
IPFW_WUNLOCK(ch);
|
||||
|
||||
@ -238,11 +233,10 @@ add_table_entry(struct ip_fw_chain *ch, struct tid_info *ti,
|
||||
if (error == 0 && (tei->flags & TEI_FLAGS_UPDATED) == 0)
|
||||
tc->count++;
|
||||
|
||||
tc->flags = aflags;
|
||||
|
||||
IPFW_UH_WUNLOCK(ch);
|
||||
|
||||
done:
|
||||
if (tc_new != NULL)
|
||||
free_table_config(ni, tc_new);
|
||||
/* Run cleaning callback anyway */
|
||||
ta->flush_entry(tei, &ta_buf);
|
||||
|
||||
@ -258,6 +252,7 @@ del_table_entry(struct ip_fw_chain *ch, struct tid_info *ti,
|
||||
struct namedobj_instance *ni;
|
||||
uint16_t kidx;
|
||||
int error;
|
||||
uint64_t aflags;
|
||||
char ta_buf[128];
|
||||
|
||||
IPFW_UH_WLOCK(ch);
|
||||
@ -272,8 +267,34 @@ del_table_entry(struct ip_fw_chain *ch, struct tid_info *ti,
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
aflags = tc->flags;
|
||||
ta = tc->ta;
|
||||
|
||||
if (aflags != 0) {
|
||||
|
||||
/*
|
||||
* Give the chance to algo to shrink its state.
|
||||
*/
|
||||
tc->no.refcnt++;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* We assume ta_buf size is enough for storing
|
||||
* prepare_del() key, so we're running under UH_LOCK here.
|
||||
*/
|
||||
memset(&ta_buf, 0, sizeof(ta_buf));
|
||||
if ((error = ta->prepare_del(tei, &ta_buf)) != 0) {
|
||||
IPFW_UH_WUNLOCK(ch);
|
||||
@ -283,11 +304,12 @@ del_table_entry(struct ip_fw_chain *ch, struct tid_info *ti,
|
||||
kidx = tc->no.kidx;
|
||||
|
||||
IPFW_WLOCK(ch);
|
||||
error = ta->del(tc->astate, KIDX_TO_TI(ch, kidx), tei, &ta_buf);
|
||||
error = ta->del(tc->astate, KIDX_TO_TI(ch, kidx), tei, &ta_buf,&aflags);
|
||||
IPFW_WUNLOCK(ch);
|
||||
|
||||
if (error == 0)
|
||||
tc->count--;
|
||||
tc->flags = aflags;
|
||||
|
||||
IPFW_UH_WUNLOCK(ch);
|
||||
|
||||
@ -296,18 +318,62 @@ del_table_entry(struct ip_fw_chain *ch, struct tid_info *ti,
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Runs callbacks to modify algo state (typically, table resize).
|
||||
*
|
||||
* Callbacks order:
|
||||
* 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
|
||||
*/
|
||||
static int
|
||||
modify_table(struct ip_fw_chain *ch, struct table_config *tc,
|
||||
struct table_algo *ta, void *ta_buf, uint64_t pflags)
|
||||
{
|
||||
struct table_info *ti;
|
||||
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);
|
||||
|
||||
error = ta->fill_mod(tc->astate, ti, &ta_buf, &pflags);
|
||||
|
||||
/*
|
||||
* prepare_mofify may return zero in @pflags to
|
||||
* indicate that modifications are not unnesessary.
|
||||
*/
|
||||
|
||||
if (error == 0 && pflags != 0) {
|
||||
/* Do actual modification */
|
||||
IPFW_WLOCK(ch);
|
||||
ta->modify(tc->astate, ti, &ta_buf, pflags);
|
||||
IPFW_WUNLOCK(ch);
|
||||
}
|
||||
|
||||
IPFW_UH_WUNLOCK(ch);
|
||||
|
||||
ta->flush_mod(ta_buf);
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
int
|
||||
ipfw_modify_table(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
|
||||
ipfw_manage_table_ent(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
|
||||
struct sockopt_data *sd)
|
||||
{
|
||||
int error;
|
||||
|
||||
switch (op3->version) {
|
||||
case 0:
|
||||
error = ipfw_modify_table_v0(ch, op3, sd);
|
||||
error = ipfw_manage_table_ent_v0(ch, op3, sd);
|
||||
break;
|
||||
case 1:
|
||||
error = ipfw_modify_table_v1(ch, op3, sd);
|
||||
error = ipfw_manage_table_ent_v1(ch, op3, sd);
|
||||
break;
|
||||
default:
|
||||
error = ENOTSUP;
|
||||
@ -324,7 +390,7 @@ ipfw_modify_table(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
|
||||
* Returns 0 on success
|
||||
*/
|
||||
static int
|
||||
ipfw_modify_table_v0(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
|
||||
ipfw_manage_table_ent_v0(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
|
||||
struct sockopt_data *sd)
|
||||
{
|
||||
ipfw_table_xentry *xent;
|
||||
@ -350,6 +416,7 @@ ipfw_modify_table_v0(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
|
||||
tei.masklen = xent->masklen;
|
||||
tei.value = xent->value;
|
||||
/* Old requests compability */
|
||||
tei.flags = TEI_FLAGS_COMPAT;
|
||||
if (xent->type == IPFW_TABLE_CIDR) {
|
||||
if (xent->len - hdrlen == sizeof(in_addr_t))
|
||||
tei.subtype = AF_INET;
|
||||
@ -371,22 +438,25 @@ ipfw_modify_table_v0(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
|
||||
/*
|
||||
* Adds or deletes record in table.
|
||||
* Data layout (v1)(current):
|
||||
* Request: [ ipfw_obj_header ipfw_obj_tentry ]
|
||||
* Request: [ ipfw_obj_header
|
||||
* ipfw_obj_ctlv(IPFW_TLV_TBLENT_LIST) [ ipfw_obj_tentry x N ]
|
||||
* ]
|
||||
*
|
||||
* Returns 0 on success
|
||||
*/
|
||||
static int
|
||||
ipfw_modify_table_v1(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
|
||||
ipfw_manage_table_ent_v1(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
|
||||
struct sockopt_data *sd)
|
||||
{
|
||||
ipfw_obj_tentry *tent;
|
||||
ipfw_obj_ctlv *ctlv;
|
||||
ipfw_obj_header *oh;
|
||||
struct tentry_info tei;
|
||||
struct tid_info ti;
|
||||
int error, read;
|
||||
|
||||
/* Check minimum header size */
|
||||
if (sd->valsize < (sizeof(*oh) + sizeof(*tent)))
|
||||
if (sd->valsize < (sizeof(*oh) + sizeof(*ctlv)))
|
||||
return (EINVAL);
|
||||
|
||||
/* Check if passed data is too long */
|
||||
@ -401,8 +471,21 @@ ipfw_modify_table_v1(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
|
||||
|
||||
read = sizeof(*oh);
|
||||
|
||||
ctlv = (ipfw_obj_ctlv *)(oh + 1);
|
||||
if (ctlv->head.length + read != sd->valsize)
|
||||
return (EINVAL);
|
||||
|
||||
/*
|
||||
* TODO: permit adding multiple entries for given table
|
||||
* at once
|
||||
*/
|
||||
if (ctlv->count != 1)
|
||||
return (EOPNOTSUPP);
|
||||
|
||||
read += sizeof(*ctlv);
|
||||
|
||||
/* Assume tentry may grow to support larger keys */
|
||||
tent = (ipfw_obj_tentry *)(oh + 1);
|
||||
tent = (ipfw_obj_tentry *)(ctlv + 1);
|
||||
if (tent->head.length < sizeof(*tent) ||
|
||||
tent->head.length + read > sd->valsize)
|
||||
return (EINVAL);
|
||||
@ -1071,8 +1154,6 @@ ipfw_create_table(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
|
||||
struct tid_info ti;
|
||||
struct namedobj_instance *ni;
|
||||
struct table_config *tc;
|
||||
struct table_algo *ta;
|
||||
uint16_t kidx;
|
||||
|
||||
if (sd->valsize != sizeof(*oh) + sizeof(ipfw_xtable_info))
|
||||
return (EINVAL);
|
||||
@ -1105,23 +1186,50 @@ ipfw_create_table(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
|
||||
IPFW_UH_RUNLOCK(ch);
|
||||
return (EEXIST);
|
||||
}
|
||||
ta = find_table_algo(CHAIN_TO_TCFG(ch), &ti, aname);
|
||||
IPFW_UH_RUNLOCK(ch);
|
||||
|
||||
return (create_table_internal(ch, &ti, aname, i->vtype));
|
||||
}
|
||||
|
||||
/*
|
||||
* Creates new table based on @ti and @aname.
|
||||
*
|
||||
* Relies on table name checking inside find_name_tlv()
|
||||
* Assume @aname to be checked and valid.
|
||||
*
|
||||
* Returns 0 on success.
|
||||
*/
|
||||
static int
|
||||
create_table_internal(struct ip_fw_chain *ch, struct tid_info *ti,
|
||||
char *aname, uint8_t vtype)
|
||||
{
|
||||
struct namedobj_instance *ni;
|
||||
struct table_config *tc;
|
||||
struct table_algo *ta;
|
||||
uint16_t kidx;
|
||||
|
||||
ni = CHAIN_TO_NI(ch);
|
||||
|
||||
ta = find_table_algo(CHAIN_TO_TCFG(ch), ti, aname);
|
||||
if (ta == NULL)
|
||||
return (ENOTSUP);
|
||||
|
||||
if ((tc = alloc_table_config(ni, &ti, ta, aname)) == NULL)
|
||||
if ((tc = alloc_table_config(ni, ti, ta, aname, vtype)) == NULL)
|
||||
return (ENOMEM);
|
||||
/* TODO: move inside alloc_table_config() */
|
||||
tc->vtype = i->vtype;
|
||||
|
||||
IPFW_UH_WLOCK(ch);
|
||||
|
||||
/* Check if table has been already created */
|
||||
if (find_table(ni, ti) != NULL) {
|
||||
IPFW_UH_WUNLOCK(ch);
|
||||
free_table_config(ni, tc);
|
||||
return (EEXIST);
|
||||
}
|
||||
|
||||
if (ipfw_objhash_alloc_idx(ni, &kidx) != 0) {
|
||||
IPFW_UH_WUNLOCK(ch);
|
||||
printf("Unable to allocate table index for table %s in set %u."
|
||||
" Consider increasing net.inet.ip.fw.tables_max",
|
||||
tname, ti.set);
|
||||
printf("Unable to allocate table index."
|
||||
" Consider increasing net.inet.ip.fw.tables_max");
|
||||
free_table_config(ni, tc);
|
||||
return (EBUSY);
|
||||
}
|
||||
@ -1692,7 +1800,7 @@ find_table(struct namedobj_instance *ni, struct tid_info *ti)
|
||||
|
||||
static struct table_config *
|
||||
alloc_table_config(struct namedobj_instance *ni, struct tid_info *ti,
|
||||
struct table_algo *ta, char *aname)
|
||||
struct table_algo *ta, char *aname, uint8_t vtype)
|
||||
{
|
||||
char *name, bname[16];
|
||||
struct table_config *tc;
|
||||
@ -1719,7 +1827,10 @@ alloc_table_config(struct namedobj_instance *ni, struct tid_info *ti,
|
||||
tc->ta = ta;
|
||||
strlcpy(tc->tablename, name, sizeof(tc->tablename));
|
||||
/* Set default value type to u32 for compability reasons */
|
||||
if (vtype == 0)
|
||||
tc->vtype = IPFW_VTYPE_U32;
|
||||
else
|
||||
tc->vtype = vtype;
|
||||
|
||||
if (ti->tlvs == NULL) {
|
||||
tc->no.compat = 1;
|
||||
@ -2058,7 +2169,7 @@ ipfw_rewrite_table_uidx(struct ip_fw_chain *chain,
|
||||
error = ENOTSUP;
|
||||
goto free;
|
||||
}
|
||||
tc = alloc_table_config(ni, &ti, ta, NULL);
|
||||
tc = alloc_table_config(ni, &ti, ta, NULL, IPFW_VTYPE_U32);
|
||||
|
||||
if (tc == NULL) {
|
||||
error = ENOMEM;
|
||||
|
@ -41,7 +41,6 @@ struct table_info {
|
||||
u_long data; /* Hints for given func */
|
||||
};
|
||||
|
||||
|
||||
/* Internal structures for handling sockopt data */
|
||||
struct tid_info {
|
||||
uint32_t set; /* table set */
|
||||
@ -61,16 +60,25 @@ struct tentry_info {
|
||||
};
|
||||
#define TEI_FLAGS_UPDATE 0x01 /* Update record if exists */
|
||||
#define TEI_FLAGS_UPDATED 0x02 /* Entry has been updated */
|
||||
#define TEI_FLAGS_COMPAT 0x04 /* Called from old ABI */
|
||||
|
||||
typedef int (ta_init)(void **ta_state, struct table_info *ti, char *data);
|
||||
typedef void (ta_destroy)(void *ta_state, struct table_info *ti);
|
||||
typedef int (ta_prepare_add)(struct tentry_info *tei, void *ta_buf);
|
||||
typedef int (ta_prepare_del)(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);
|
||||
struct tentry_info *tei, void *ta_buf, uint64_t *pflags);
|
||||
typedef int (ta_del)(void *ta_state, struct table_info *ti,
|
||||
struct tentry_info *tei, void *ta_buf);
|
||||
struct tentry_info *tei, void *ta_buf, uint64_t *pflags);
|
||||
typedef void (ta_flush_entry)(struct tentry_info *tei, void *ta_buf);
|
||||
|
||||
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);
|
||||
typedef int (ta_modify)(void *ta_state, struct table_info *ti,
|
||||
void *ta_buf, uint64_t pflags);
|
||||
typedef void (ta_flush_mod)(void *ta_buf);
|
||||
|
||||
typedef void (ta_print_config)(void *ta_state, struct table_info *ti, char *buf,
|
||||
size_t bufsize);
|
||||
|
||||
@ -93,6 +101,10 @@ struct table_algo {
|
||||
ta_add *add;
|
||||
ta_del *del;
|
||||
ta_flush_entry *flush_entry;
|
||||
ta_prepare_mod *prepare_mod;
|
||||
ta_fill_mod *fill_mod;
|
||||
ta_modify *modify;
|
||||
ta_flush_mod *flush_mod;
|
||||
ta_foreach *foreach;
|
||||
ta_dump_tentry *dump_tentry;
|
||||
ta_print_config *print_config;
|
||||
@ -116,7 +128,7 @@ int ipfw_find_table_entry(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
|
||||
struct sockopt_data *sd);
|
||||
int ipfw_create_table(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
|
||||
struct sockopt_data *sd);
|
||||
int ipfw_modify_table(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
|
||||
int ipfw_manage_table_ent(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
|
||||
struct sockopt_data *sd);
|
||||
int ipfw_flush_table(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
|
||||
struct sockopt_data *sd);
|
||||
|
@ -380,7 +380,7 @@ ta_prepare_add_cidr(struct tentry_info *tei, void *ta_buf)
|
||||
|
||||
static int
|
||||
ta_add_cidr(void *ta_state, struct table_info *ti,
|
||||
struct tentry_info *tei, void *ta_buf)
|
||||
struct tentry_info *tei, void *ta_buf, uint64_t *pflags)
|
||||
{
|
||||
struct radix_node_head *rnh;
|
||||
struct radix_node *rn;
|
||||
@ -488,7 +488,7 @@ ta_prepare_del_cidr(struct tentry_info *tei, void *ta_buf)
|
||||
|
||||
static int
|
||||
ta_del_cidr(void *ta_state, struct table_info *ti,
|
||||
struct tentry_info *tei, void *ta_buf)
|
||||
struct tentry_info *tei, void *ta_buf, uint64_t *pflags)
|
||||
{
|
||||
struct radix_node_head *rnh;
|
||||
struct radix_node *rn;
|
||||
@ -644,7 +644,7 @@ ta_prepare_add_iface(struct tentry_info *tei, void *ta_buf)
|
||||
|
||||
static int
|
||||
ta_add_iface(void *ta_state, struct table_info *ti,
|
||||
struct tentry_info *tei, void *ta_buf)
|
||||
struct tentry_info *tei, void *ta_buf, uint64_t *pflags)
|
||||
{
|
||||
struct radix_node_head *rnh;
|
||||
struct radix_node *rn;
|
||||
@ -718,7 +718,7 @@ ta_prepare_del_iface(struct tentry_info *tei, void *ta_buf)
|
||||
|
||||
static int
|
||||
ta_del_iface(void *ta_state, struct table_info *ti,
|
||||
struct tentry_info *tei, void *ta_buf)
|
||||
struct tentry_info *tei, void *ta_buf, uint64_t *pflags)
|
||||
{
|
||||
struct radix_node_head *rnh;
|
||||
struct radix_node *rn;
|
||||
|
Loading…
Reference in New Issue
Block a user