* Add IP_FW_TABLE_XCREATE / IP_FW_TABLE_XMODIFY opcodes.
* Add 'algoname' string to ipfw_xtable_info permitting to specify lookup algoritm with parameters. * Rework part of ipfw_rewrite_table_uidx() Sponsored by: Yandex LLC
This commit is contained in:
parent
9c3c43aa77
commit
9490a62716
@ -81,10 +81,12 @@ typedef struct _ip_fw3_opheader {
|
|||||||
#define IP_FW_TABLE_XGETSIZE 88 /* get table size (deprecated) */
|
#define IP_FW_TABLE_XGETSIZE 88 /* get table size (deprecated) */
|
||||||
#define IP_FW_TABLE_XLIST 89 /* list table contents */
|
#define IP_FW_TABLE_XLIST 89 /* list table contents */
|
||||||
#define IP_FW_TABLE_XDESTROY 90 /* destroy table */
|
#define IP_FW_TABLE_XDESTROY 90 /* destroy table */
|
||||||
#define IP_FW_TABLES_XGETSIZE 91 /* get size for table/etc list */
|
#define IP_FW_TABLES_XGETSIZE 91 /* get size for tables list */
|
||||||
#define IP_FW_TABLES_XLIST 92 /* list all objects of given type */
|
#define IP_FW_TABLES_XLIST 92 /* list all tables */
|
||||||
#define IP_FW_TABLE_XINFO 93 /* request info for one object */
|
#define IP_FW_TABLE_XINFO 93 /* request info for one table */
|
||||||
#define IP_FW_TABLE_XFLUSH 94 /* flush data for given object */
|
#define IP_FW_TABLE_XFLUSH 94 /* flush table data */
|
||||||
|
#define IP_FW_TABLE_XCREATE 95 /* create new table */
|
||||||
|
#define IP_FW_TABLE_XMODIFY 96 /* modify existing table */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Usage guidelines:
|
* Usage guidelines:
|
||||||
@ -693,7 +695,7 @@ typedef struct _ipfw_obj_ntlv {
|
|||||||
|
|
||||||
typedef struct _ipfw_xtable_info {
|
typedef struct _ipfw_xtable_info {
|
||||||
uint8_t type; /* table type (cidr,iface,..) */
|
uint8_t type; /* table type (cidr,iface,..) */
|
||||||
uint8_t ftype; /* format table type */
|
uint8_t ftype; /* table value format type */
|
||||||
uint8_t atype; /* algorithm type */
|
uint8_t atype; /* algorithm type */
|
||||||
uint8_t spare0;
|
uint8_t spare0;
|
||||||
uint32_t set; /* set table is in */
|
uint32_t set; /* set table is in */
|
||||||
@ -702,6 +704,7 @@ typedef struct _ipfw_xtable_info {
|
|||||||
uint32_t count; /* Number of records */
|
uint32_t count; /* Number of records */
|
||||||
uint32_t size; /* Total size of records */
|
uint32_t size; /* Total size of records */
|
||||||
char tablename[64]; /* table name */
|
char tablename[64]; /* table name */
|
||||||
|
char algoname[32]; /* algorithm name */
|
||||||
} ipfw_xtable_info;
|
} ipfw_xtable_info;
|
||||||
|
|
||||||
#define IPFW_OBJTYPE_TABLE 1
|
#define IPFW_OBJTYPE_TABLE 1
|
||||||
|
@ -362,6 +362,8 @@ struct named_object *ipfw_objhash_lookup_name(struct namedobj_instance *ni,
|
|||||||
uint32_t set, char *name);
|
uint32_t set, char *name);
|
||||||
struct named_object *ipfw_objhash_lookup_idx(struct namedobj_instance *ni,
|
struct named_object *ipfw_objhash_lookup_idx(struct namedobj_instance *ni,
|
||||||
uint32_t set, uint16_t idx);
|
uint32_t set, uint16_t idx);
|
||||||
|
int ipfw_objhash_same_name(struct namedobj_instance *ni, struct named_object *a,
|
||||||
|
struct named_object *b);
|
||||||
void ipfw_objhash_add(struct namedobj_instance *ni, struct named_object *no);
|
void ipfw_objhash_add(struct namedobj_instance *ni, struct named_object *no);
|
||||||
void ipfw_objhash_del(struct namedobj_instance *ni, struct named_object *no);
|
void ipfw_objhash_del(struct namedobj_instance *ni, struct named_object *no);
|
||||||
uint32_t ipfw_objhash_count(struct namedobj_instance *ni);
|
uint32_t ipfw_objhash_count(struct namedobj_instance *ni);
|
||||||
|
@ -1172,6 +1172,14 @@ ipfw_ctl(struct sockopt *sopt)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
/*--- TABLE opcodes ---*/
|
/*--- TABLE opcodes ---*/
|
||||||
|
case IP_FW_TABLE_XCREATE: /* IP_FW3 */
|
||||||
|
case IP_FW_TABLE_XMODIFY: /* IP_FW3 */
|
||||||
|
if (opt == IP_FW_TABLE_XCREATE)
|
||||||
|
error = ipfw_create_table(chain, sopt, op3);
|
||||||
|
else
|
||||||
|
error= ipfw_modify_table(chain, sopt, op3);
|
||||||
|
break;
|
||||||
|
|
||||||
case IP_FW_TABLE_XDESTROY: /* IP_FW3 */
|
case IP_FW_TABLE_XDESTROY: /* IP_FW3 */
|
||||||
case IP_FW_TABLE_XFLUSH: /* IP_FW3 */
|
case IP_FW_TABLE_XFLUSH: /* IP_FW3 */
|
||||||
{
|
{
|
||||||
@ -1705,6 +1713,17 @@ ipfw_objhash_lookup_idx(struct namedobj_instance *ni, uint32_t set,
|
|||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
ipfw_objhash_same_name(struct namedobj_instance *ni, struct named_object *a,
|
||||||
|
struct named_object *b)
|
||||||
|
{
|
||||||
|
|
||||||
|
if ((strcmp(a->name, b->name) == 0) && a->set == b->set)
|
||||||
|
return (1);
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ipfw_objhash_add(struct namedobj_instance *ni, struct named_object *no)
|
ipfw_objhash_add(struct namedobj_instance *ni, struct named_object *no)
|
||||||
{
|
{
|
||||||
|
@ -69,8 +69,9 @@ __FBSDID("$FreeBSD$");
|
|||||||
* `ta->atype` represents exact lookup algorithm.
|
* `ta->atype` represents exact lookup algorithm.
|
||||||
* For example, we can use more efficient search schemes if we plan
|
* For example, we can use more efficient search schemes if we plan
|
||||||
* to use some specific table for storing host-routes only.
|
* to use some specific table for storing host-routes only.
|
||||||
* `ftype` is pure userland field helping to properly format table data
|
* `ftype` (at the moment )is pure userland field helping to properly
|
||||||
* e.g. "value is IPv4 nexthop" or "key is port number"
|
* format value data e.g. "value is IPv4 nexthop" or "value is DSCP"
|
||||||
|
* or "value is port".
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
struct table_config {
|
struct table_config {
|
||||||
@ -95,7 +96,7 @@ struct tables_config {
|
|||||||
static struct table_config *find_table(struct namedobj_instance *ni,
|
static struct table_config *find_table(struct namedobj_instance *ni,
|
||||||
struct tid_info *ti);
|
struct tid_info *ti);
|
||||||
static struct table_config *alloc_table_config(struct namedobj_instance *ni,
|
static struct table_config *alloc_table_config(struct namedobj_instance *ni,
|
||||||
struct tid_info *ti, struct table_algo *ta);
|
struct tid_info *ti, struct table_algo *ta, char *adata);
|
||||||
static void free_table_config(struct namedobj_instance *ni,
|
static void free_table_config(struct namedobj_instance *ni,
|
||||||
struct table_config *tc);
|
struct table_config *tc);
|
||||||
static void link_table(struct ip_fw_chain *chain, struct table_config *tc);
|
static void link_table(struct ip_fw_chain *chain, struct table_config *tc);
|
||||||
@ -114,7 +115,7 @@ static int ipfw_dump_table_v1(struct ip_fw_chain *ch, struct sockopt *sopt,
|
|||||||
ip_fw3_opheader *op3, size_t valsize);
|
ip_fw3_opheader *op3, size_t valsize);
|
||||||
|
|
||||||
static struct table_algo *find_table_algo(struct tables_config *tableconf,
|
static struct table_algo *find_table_algo(struct tables_config *tableconf,
|
||||||
struct tid_info *ti);
|
struct tid_info *ti, char *name);
|
||||||
|
|
||||||
#define CHAIN_TO_TCFG(chain) ((struct tables_config *)(chain)->tblcfg)
|
#define CHAIN_TO_TCFG(chain) ((struct tables_config *)(chain)->tblcfg)
|
||||||
#define CHAIN_TO_NI(chain) (CHAIN_TO_TCFG(chain)->namehash)
|
#define CHAIN_TO_NI(chain) (CHAIN_TO_TCFG(chain)->namehash)
|
||||||
@ -161,10 +162,10 @@ ipfw_add_table_entry(struct ip_fw_chain *ch, struct tid_info *ti,
|
|||||||
tc_new = NULL;
|
tc_new = NULL;
|
||||||
if (ta == NULL) {
|
if (ta == NULL) {
|
||||||
/* Table not found. We have to create new one */
|
/* Table not found. We have to create new one */
|
||||||
if ((ta = find_table_algo(CHAIN_TO_TCFG(ch), ti)) == NULL)
|
if ((ta = find_table_algo(CHAIN_TO_TCFG(ch), ti, NULL)) == NULL)
|
||||||
return (ENOTSUP);
|
return (ENOTSUP);
|
||||||
|
|
||||||
tc_new = alloc_table_config(ni, ti, ta);
|
tc_new = alloc_table_config(ni, ti, ta, NULL);
|
||||||
if (tc_new == NULL)
|
if (tc_new == NULL)
|
||||||
return (ENOMEM);
|
return (ENOMEM);
|
||||||
}
|
}
|
||||||
@ -330,9 +331,10 @@ ipfw_flush_table(struct ip_fw_chain *ch, struct tid_info *ti)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Stage 2: allocate new table instance using same algo.
|
* Stage 2: allocate new table instance using same algo.
|
||||||
|
* TODO: pass startup parametes somehow.
|
||||||
*/
|
*/
|
||||||
memset(&ti_new, 0, sizeof(struct table_info));
|
memset(&ti_new, 0, sizeof(struct table_info));
|
||||||
if ((error = ta->init(&astate_new, &ti_new)) != 0) {
|
if ((error = ta->init(&astate_new, &ti_new, NULL)) != 0) {
|
||||||
IPFW_UH_WLOCK(ch);
|
IPFW_UH_WLOCK(ch);
|
||||||
tc->no.refcnt--;
|
tc->no.refcnt--;
|
||||||
IPFW_UH_WUNLOCK(ch);
|
IPFW_UH_WUNLOCK(ch);
|
||||||
@ -884,6 +886,99 @@ ipfw_dump_table_v0(struct ip_fw_chain *ch, struct sockopt *sopt,
|
|||||||
return (error);
|
return (error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* High-level setsockopt cmds
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
ipfw_modify_table(struct ip_fw_chain *ch, struct sockopt *sopt,
|
||||||
|
ip_fw3_opheader *op3)
|
||||||
|
{
|
||||||
|
|
||||||
|
return (ENOTSUP);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Creates new table.
|
||||||
|
* Data layout:
|
||||||
|
* Request: [ ipfw_obj_header ipfw_xtable_info ]
|
||||||
|
*
|
||||||
|
* Returns 0 on success
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
ipfw_create_table(struct ip_fw_chain *ch, struct sockopt *sopt,
|
||||||
|
ip_fw3_opheader *op3)
|
||||||
|
{
|
||||||
|
struct _ipfw_obj_header *oh;
|
||||||
|
ipfw_xtable_info *i;
|
||||||
|
char *tname, *aname;
|
||||||
|
struct tid_info ti;
|
||||||
|
struct namedobj_instance *ni;
|
||||||
|
struct table_config *tc;
|
||||||
|
struct table_algo *ta;
|
||||||
|
uint16_t kidx;
|
||||||
|
|
||||||
|
if (sopt->sopt_valsize < sizeof(*oh) + sizeof(ipfw_xtable_info))
|
||||||
|
return (EINVAL);
|
||||||
|
|
||||||
|
oh = (struct _ipfw_obj_header *)op3;
|
||||||
|
i = (ipfw_xtable_info *)(oh + 1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Verify user-supplied strings.
|
||||||
|
* Check for null-terminated/zero-lenght strings/
|
||||||
|
*/
|
||||||
|
tname = i->tablename;
|
||||||
|
aname = i->algoname;
|
||||||
|
if (strnlen(tname, sizeof(i->tablename)) == sizeof(i->tablename) ||
|
||||||
|
tname[0] == '\0' ||
|
||||||
|
strnlen(aname, sizeof(i->algoname)) == sizeof(i->algoname))
|
||||||
|
return (EINVAL);
|
||||||
|
|
||||||
|
if (aname[0] == '\0') {
|
||||||
|
/* Use default algorithm */
|
||||||
|
aname = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
objheader_to_ti(oh, &ti);
|
||||||
|
|
||||||
|
ni = CHAIN_TO_NI(ch);
|
||||||
|
|
||||||
|
IPFW_UH_RLOCK(ch);
|
||||||
|
if ((tc = find_table(ni, &ti)) != NULL) {
|
||||||
|
IPFW_UH_RUNLOCK(ch);
|
||||||
|
return (EEXIST);
|
||||||
|
}
|
||||||
|
ta = find_table_algo(CHAIN_TO_TCFG(ch), &ti, aname);
|
||||||
|
IPFW_UH_RUNLOCK(ch);
|
||||||
|
|
||||||
|
if (ta == NULL)
|
||||||
|
return (ENOTSUP);
|
||||||
|
|
||||||
|
if ((tc = alloc_table_config(ni, &ti, ta, aname)) == NULL)
|
||||||
|
return (ENOMEM);
|
||||||
|
|
||||||
|
IPFW_UH_WLOCK(ch);
|
||||||
|
if (ipfw_objhash_alloc_idx(ni, ti.set, &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);
|
||||||
|
free_table_config(ni, tc);
|
||||||
|
return (EBUSY);
|
||||||
|
}
|
||||||
|
|
||||||
|
tc->no.kidx = kidx;
|
||||||
|
|
||||||
|
IPFW_WLOCK(ch);
|
||||||
|
link_table(ch, tc);
|
||||||
|
IPFW_WUNLOCK(ch);
|
||||||
|
|
||||||
|
IPFW_UH_WUNLOCK(ch);
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Checks if supplied buffer size is "reasonable".
|
* Checks if supplied buffer size is "reasonable".
|
||||||
* Permit valsize between current needed size and
|
* Permit valsize between current needed size and
|
||||||
@ -1059,7 +1154,9 @@ ipfw_dump_table_legacy(struct ip_fw_chain *ch, struct tid_info *ti,
|
|||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Dumps table entry in eXtended format (current).
|
||||||
|
*/
|
||||||
static int
|
static int
|
||||||
dump_table_xentry(void *e, void *arg)
|
dump_table_xentry(void *e, void *arg)
|
||||||
{
|
{
|
||||||
@ -1089,11 +1186,13 @@ dump_table_xentry(void *e, void *arg)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Finds algoritm by index or table type
|
* Finds algoritm by index, table type or supplied name
|
||||||
*/
|
*/
|
||||||
static struct table_algo *
|
static struct table_algo *
|
||||||
find_table_algo(struct tables_config *tcfg, struct tid_info *ti)
|
find_table_algo(struct tables_config *tcfg, struct tid_info *ti, char *name)
|
||||||
{
|
{
|
||||||
|
int i, l;
|
||||||
|
struct table_algo *ta;
|
||||||
|
|
||||||
/* Search by index */
|
/* Search by index */
|
||||||
if (ti->atype != 0) {
|
if (ti->atype != 0) {
|
||||||
@ -1102,6 +1201,30 @@ find_table_algo(struct tables_config *tcfg, struct tid_info *ti)
|
|||||||
return (tcfg->algo[ti->atype]);
|
return (tcfg->algo[ti->atype]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Search by name if supplied */
|
||||||
|
if (name != NULL) {
|
||||||
|
/* TODO: better search */
|
||||||
|
for (i = 1; i <= tcfg->algo_count; i++) {
|
||||||
|
ta = tcfg->algo[i];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* One can supply additional algorithm
|
||||||
|
* parameters so we compare only the first word
|
||||||
|
* of supplied name:
|
||||||
|
* 'hash_cidr hsize=32'
|
||||||
|
* '^^^^^^^^^'
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
l = strlen(ta->name);
|
||||||
|
if (strncmp(name, ta->name, l) == 0) {
|
||||||
|
if (name[l] == '\0' || name[l] == ' ')
|
||||||
|
return (ta);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
/* Search by type */
|
/* Search by type */
|
||||||
switch (ti->type) {
|
switch (ti->type) {
|
||||||
case IPFW_TABLE_CIDR:
|
case IPFW_TABLE_CIDR:
|
||||||
@ -1272,7 +1395,7 @@ find_table(struct namedobj_instance *ni, struct tid_info *ti)
|
|||||||
|
|
||||||
static struct table_config *
|
static struct table_config *
|
||||||
alloc_table_config(struct namedobj_instance *ni, struct tid_info *ti,
|
alloc_table_config(struct namedobj_instance *ni, struct tid_info *ti,
|
||||||
struct table_algo *ta)
|
struct table_algo *ta, char *aname)
|
||||||
{
|
{
|
||||||
char *name, bname[16];
|
char *name, bname[16];
|
||||||
struct table_config *tc;
|
struct table_config *tc;
|
||||||
@ -1300,7 +1423,7 @@ alloc_table_config(struct namedobj_instance *ni, struct tid_info *ti,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Preallocate data structures for new tables */
|
/* Preallocate data structures for new tables */
|
||||||
error = ta->init(&tc->astate, &tc->ti);
|
error = ta->init(&tc->astate, &tc->ti, aname);
|
||||||
if (error != 0) {
|
if (error != 0) {
|
||||||
free(tc, M_IPFW);
|
free(tc, M_IPFW);
|
||||||
return (NULL);
|
return (NULL);
|
||||||
@ -1371,45 +1494,89 @@ unlink_table(struct ip_fw_chain *ch, struct table_config *tc)
|
|||||||
/*
|
/*
|
||||||
* Finds named object by @uidx number.
|
* Finds named object by @uidx number.
|
||||||
* Refs found object, allocate new index for non-existing object.
|
* Refs found object, allocate new index for non-existing object.
|
||||||
* Fills in @pidx with userland/kernel indexes.
|
* Fills in @oib with userland/kernel indexes.
|
||||||
|
* First free oidx pointer is saved back in @oib.
|
||||||
*
|
*
|
||||||
* Returns 0 on success.
|
* Returns 0 on success.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
bind_table(struct namedobj_instance *ni, struct rule_check_info *ci,
|
bind_table_rule(struct ip_fw_chain *ch, struct ip_fw *rule,
|
||||||
struct obj_idx *pidx, struct tid_info *ti)
|
struct rule_check_info *ci, struct obj_idx **oib, struct tid_info *ti)
|
||||||
{
|
{
|
||||||
struct table_config *tc;
|
struct table_config *tc;
|
||||||
|
struct namedobj_instance *ni;
|
||||||
|
struct named_object *no;
|
||||||
|
int error, l, cmdlen;
|
||||||
|
ipfw_insn *cmd;
|
||||||
|
struct obj_idx *pidx, *p;
|
||||||
|
|
||||||
pidx->uidx = ti->uidx;
|
pidx = *oib;
|
||||||
pidx->type = ti->type;
|
l = rule->cmd_len;
|
||||||
|
cmd = rule->cmd;
|
||||||
|
cmdlen = 0;
|
||||||
|
error = 0;
|
||||||
|
|
||||||
tc = find_table(ni, ti);
|
IPFW_UH_WLOCK(ch);
|
||||||
|
ni = CHAIN_TO_NI(ch);
|
||||||
|
|
||||||
if (tc == NULL) {
|
for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) {
|
||||||
/* Try to acquire refcount */
|
cmdlen = F_LEN(cmd);
|
||||||
|
|
||||||
|
if (classify_table_opcode(cmd, &ti->uidx, &ti->type) != 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
pidx->uidx = ti->uidx;
|
||||||
|
pidx->type = ti->type;
|
||||||
|
|
||||||
|
if ((tc = find_table(ni, ti)) != NULL) {
|
||||||
|
if (tc->no.type != ti->type) {
|
||||||
|
/* Incompatible types */
|
||||||
|
error = EINVAL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Reference found table and save kidx */
|
||||||
|
tc->no.refcnt++;
|
||||||
|
pidx->kidx = tc->no.kidx;
|
||||||
|
pidx++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Table not found. Allocate new index and save for later */
|
||||||
if (ipfw_objhash_alloc_idx(ni, ti->set, &pidx->kidx) != 0) {
|
if (ipfw_objhash_alloc_idx(ni, ti->set, &pidx->kidx) != 0) {
|
||||||
printf("Unable to allocate table index in set %u."
|
printf("Unable to allocate table index in set %u."
|
||||||
" Consider increasing net.inet.ip.fw.tables_max",
|
" Consider increasing net.inet.ip.fw.tables_max",
|
||||||
ti->set);
|
ti->set);
|
||||||
return (EBUSY);
|
error = EBUSY;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
pidx->new = 1;
|
|
||||||
ci->new_tables++;
|
ci->new_tables++;
|
||||||
|
pidx->new = 1;
|
||||||
return (0);
|
pidx++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check if table type if valid first */
|
if (error != 0) {
|
||||||
if (tc->no.type != ti->type)
|
/* Unref everything we have already done */
|
||||||
return (EINVAL);
|
for (p = *oib; p < pidx; p++) {
|
||||||
|
if (p->new != 0) {
|
||||||
|
ipfw_objhash_free_idx(ni, ci->tableset,p->kidx);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
tc->no.refcnt++;
|
/* Find & unref by existing idx */
|
||||||
|
no = ipfw_objhash_lookup_idx(ni, ci->tableset, p->kidx);
|
||||||
|
KASSERT(no != NULL, ("Ref'd table %d disappeared",
|
||||||
|
p->kidx));
|
||||||
|
|
||||||
pidx->kidx = tc->no.kidx;
|
no->refcnt--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IPFW_UH_WUNLOCK(ch);
|
||||||
|
|
||||||
return (0);
|
*oib = pidx;
|
||||||
|
|
||||||
|
return (error);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1477,24 +1644,27 @@ ipfw_rewrite_table_uidx(struct ip_fw_chain *chain,
|
|||||||
struct table_algo *ta;
|
struct table_algo *ta;
|
||||||
struct namedobj_instance *ni;
|
struct namedobj_instance *ni;
|
||||||
struct named_object *no, *no_n, *no_tmp;
|
struct named_object *no, *no_n, *no_tmp;
|
||||||
struct obj_idx *pidx, *p, *oib;
|
struct obj_idx *p, *pidx_first, *pidx_last;
|
||||||
struct namedobjects_head nh;
|
struct namedobjects_head nh;
|
||||||
struct tid_info ti;
|
struct tid_info ti;
|
||||||
|
|
||||||
ni = CHAIN_TO_NI(chain);
|
ni = CHAIN_TO_NI(chain);
|
||||||
|
|
||||||
|
/* Prepare queue to store configs */
|
||||||
|
TAILQ_INIT(&nh);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Prepare an array for storing opcode indices.
|
* Prepare an array for storing opcode indices.
|
||||||
* Use stack allocation by default.
|
* Use stack allocation by default.
|
||||||
*/
|
*/
|
||||||
if (ci->table_opcodes <= (sizeof(ci->obuf)/sizeof(ci->obuf[0]))) {
|
if (ci->table_opcodes <= (sizeof(ci->obuf)/sizeof(ci->obuf[0]))) {
|
||||||
/* Stack */
|
/* Stack */
|
||||||
pidx = ci->obuf;
|
pidx_first = ci->obuf;
|
||||||
} else
|
} else
|
||||||
pidx = malloc(ci->table_opcodes * sizeof(struct obj_idx),
|
pidx_first = malloc(ci->table_opcodes * sizeof(struct obj_idx),
|
||||||
M_IPFW, M_WAITOK | M_ZERO);
|
M_IPFW, M_WAITOK | M_ZERO);
|
||||||
|
|
||||||
oib = pidx;
|
pidx_last = pidx_first;
|
||||||
error = 0;
|
error = 0;
|
||||||
|
|
||||||
type = 0;
|
type = 0;
|
||||||
@ -1508,72 +1678,24 @@ ipfw_rewrite_table_uidx(struct ip_fw_chain *chain,
|
|||||||
ti.tlen = ci->tlen;
|
ti.tlen = ci->tlen;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Stage 1: reference existing tables and determine number
|
* Stage 1: reference existing tables, determine number
|
||||||
* of tables we need to allocate
|
* of tables we need to allocate and allocate indexes for each.
|
||||||
*/
|
*/
|
||||||
IPFW_UH_WLOCK(chain);
|
error = bind_table_rule(chain, ci->krule, ci, &pidx_last, &ti);
|
||||||
|
|
||||||
l = ci->krule->cmd_len;
|
|
||||||
cmd = ci->krule->cmd;
|
|
||||||
cmdlen = 0;
|
|
||||||
for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) {
|
|
||||||
cmdlen = F_LEN(cmd);
|
|
||||||
|
|
||||||
if (classify_table_opcode(cmd, &ti.uidx, &ti.type) != 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Got table opcode with necessary info.
|
|
||||||
* Try to reference existing tables and allocate
|
|
||||||
* indices for non-existing one while holding write lock.
|
|
||||||
*/
|
|
||||||
if ((error = bind_table(ni, ci, pidx, &ti)) != 0) {
|
|
||||||
printf("error!\n");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* @pidx stores either existing ref'd table id or new one.
|
|
||||||
* Move to next index
|
|
||||||
*/
|
|
||||||
|
|
||||||
pidx++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (error != 0) {
|
if (error != 0) {
|
||||||
/* Unref everything we have already done */
|
if (pidx_first != ci->obuf)
|
||||||
for (p = oib; p < pidx; p++) {
|
free(pidx_first, M_IPFW);
|
||||||
if (p->new != 0) {
|
|
||||||
ipfw_objhash_free_idx(ni, ci->tableset,p->kidx);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Find & unref by existing idx */
|
|
||||||
no = ipfw_objhash_lookup_idx(ni, ci->tableset, p->kidx);
|
|
||||||
KASSERT(no!=NULL, ("Ref'd table %d disappeared",
|
|
||||||
p->kidx));
|
|
||||||
|
|
||||||
no->refcnt--;
|
|
||||||
}
|
|
||||||
|
|
||||||
IPFW_UH_WUNLOCK(chain);
|
|
||||||
|
|
||||||
if (oib != ci->obuf)
|
|
||||||
free(oib, M_IPFW);
|
|
||||||
|
|
||||||
return (error);
|
return (error);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPFW_UH_WUNLOCK(chain);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Stage 2: allocate table configs for every non-existent table
|
* Stage 2: allocate table configs for every non-existent table
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Prepare queue to store configs */
|
|
||||||
TAILQ_INIT(&nh);
|
|
||||||
if (ci->new_tables > 0) {
|
if (ci->new_tables > 0) {
|
||||||
for (p = oib; p < pidx; p++) {
|
for (p = pidx_first; p < pidx_last; p++) {
|
||||||
if (p->new == 0)
|
if (p->new == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -1582,12 +1704,12 @@ ipfw_rewrite_table_uidx(struct ip_fw_chain *chain,
|
|||||||
ti.type = p->type;
|
ti.type = p->type;
|
||||||
ti.atype = 0;
|
ti.atype = 0;
|
||||||
|
|
||||||
ta = find_table_algo(CHAIN_TO_TCFG(chain), &ti);
|
ta = find_table_algo(CHAIN_TO_TCFG(chain), &ti, NULL);
|
||||||
if (ta == NULL) {
|
if (ta == NULL) {
|
||||||
error = ENOTSUP;
|
error = ENOTSUP;
|
||||||
goto free;
|
goto free;
|
||||||
}
|
}
|
||||||
tc = alloc_table_config(ni, &ti, ta);
|
tc = alloc_table_config(ni, &ti, ta, NULL);
|
||||||
|
|
||||||
if (tc == NULL) {
|
if (tc == NULL) {
|
||||||
error = ENOMEM;
|
error = ENOMEM;
|
||||||
@ -1607,7 +1729,7 @@ ipfw_rewrite_table_uidx(struct ip_fw_chain *chain,
|
|||||||
*/
|
*/
|
||||||
TAILQ_FOREACH(no, &nh, nn_next) {
|
TAILQ_FOREACH(no, &nh, nn_next) {
|
||||||
TAILQ_FOREACH(no_tmp, &nh, nn_next) {
|
TAILQ_FOREACH(no_tmp, &nh, nn_next) {
|
||||||
if (strcmp(no->name, no_tmp->name) != 0)
|
if (ipfw_objhash_same_name(ni, no, no_tmp) == 0)
|
||||||
continue;
|
continue;
|
||||||
if (no->type != no_tmp->type) {
|
if (no->type != no_tmp->type) {
|
||||||
error = EINVAL;
|
error = EINVAL;
|
||||||
@ -1649,7 +1771,6 @@ ipfw_rewrite_table_uidx(struct ip_fw_chain *chain,
|
|||||||
* We have to rollback everything.
|
* We have to rollback everything.
|
||||||
*/
|
*/
|
||||||
IPFW_UH_WUNLOCK(chain);
|
IPFW_UH_WUNLOCK(chain);
|
||||||
|
|
||||||
goto free;
|
goto free;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1662,24 +1783,28 @@ ipfw_rewrite_table_uidx(struct ip_fw_chain *chain,
|
|||||||
IPFW_WLOCK(chain);
|
IPFW_WLOCK(chain);
|
||||||
TAILQ_FOREACH_SAFE(no, &nh, nn_next, no_tmp) {
|
TAILQ_FOREACH_SAFE(no, &nh, nn_next, no_tmp) {
|
||||||
no_n = ipfw_objhash_lookup_name(ni, no->set, no->name);
|
no_n = ipfw_objhash_lookup_name(ni, no->set, no->name);
|
||||||
if (no_n != NULL) {
|
|
||||||
/* Increase refcount for existing table */
|
|
||||||
no_n->refcnt++;
|
|
||||||
/* Keep oib array in sync: update kindx */
|
|
||||||
for (p = oib; p < pidx; p++) {
|
|
||||||
if (p->kidx == no->kidx) {
|
|
||||||
p->kidx = no_n->kidx;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (no_n == NULL) {
|
||||||
|
/* New table. Attach to runtime hash */
|
||||||
|
TAILQ_REMOVE(&nh, no, nn_next);
|
||||||
|
link_table(chain, (struct table_config *)no);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* New table. Attach to runtime hash */
|
/*
|
||||||
TAILQ_REMOVE(&nh, no, nn_next);
|
* Newly-allocated table with the same type.
|
||||||
|
* Reference it and update out @pidx array
|
||||||
link_table(chain, (struct table_config *)no);
|
* rewrite info.
|
||||||
|
*/
|
||||||
|
no_n->refcnt++;
|
||||||
|
/* Keep oib array in sync: update kidx */
|
||||||
|
for (p = pidx_first; p < pidx_last; p++) {
|
||||||
|
if (p->kidx != no->kidx)
|
||||||
|
continue;
|
||||||
|
/* Update kidx */
|
||||||
|
p->kidx = no_n->kidx;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
IPFW_WUNLOCK(chain);
|
IPFW_WUNLOCK(chain);
|
||||||
}
|
}
|
||||||
@ -1688,14 +1813,14 @@ ipfw_rewrite_table_uidx(struct ip_fw_chain *chain,
|
|||||||
l = ci->krule->cmd_len;
|
l = ci->krule->cmd_len;
|
||||||
cmd = ci->krule->cmd;
|
cmd = ci->krule->cmd;
|
||||||
cmdlen = 0;
|
cmdlen = 0;
|
||||||
pidx = oib;
|
p = pidx_first;
|
||||||
for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) {
|
for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) {
|
||||||
cmdlen = F_LEN(cmd);
|
cmdlen = F_LEN(cmd);
|
||||||
|
|
||||||
if (classify_table_opcode(cmd, &uidx, &type) != 0)
|
if (classify_table_opcode(cmd, &uidx, &type) != 0)
|
||||||
continue;
|
continue;
|
||||||
update_table_opcode(cmd, pidx->kidx);
|
update_table_opcode(cmd, p->kidx);
|
||||||
pidx++;
|
p++;
|
||||||
}
|
}
|
||||||
|
|
||||||
IPFW_UH_WUNLOCK(chain);
|
IPFW_UH_WUNLOCK(chain);
|
||||||
@ -1706,11 +1831,20 @@ ipfw_rewrite_table_uidx(struct ip_fw_chain *chain,
|
|||||||
* Stage 4: free resources
|
* Stage 4: free resources
|
||||||
*/
|
*/
|
||||||
free:
|
free:
|
||||||
TAILQ_FOREACH_SAFE(no, &nh, nn_next, no_tmp)
|
if (!TAILQ_EMPTY(&nh)) {
|
||||||
free_table_config(ni, tc);
|
/* Free indexes first */
|
||||||
|
IPFW_UH_WLOCK(chain);
|
||||||
|
TAILQ_FOREACH_SAFE(no, &nh, nn_next, no_tmp) {
|
||||||
|
ipfw_objhash_free_idx(ni, ci->tableset, no->kidx);
|
||||||
|
}
|
||||||
|
IPFW_UH_WUNLOCK(chain);
|
||||||
|
/* Free configs */
|
||||||
|
TAILQ_FOREACH_SAFE(no, &nh, nn_next, no_tmp)
|
||||||
|
free_table_config(ni, tc);
|
||||||
|
}
|
||||||
|
|
||||||
if (oib != ci->obuf)
|
if (pidx_first != ci->obuf)
|
||||||
free(oib, M_IPFW);
|
free(pidx_first, M_IPFW);
|
||||||
|
|
||||||
return (error);
|
return (error);
|
||||||
}
|
}
|
||||||
|
@ -50,7 +50,7 @@ struct tentry_info {
|
|||||||
uint32_t value; /* value */
|
uint32_t value; /* value */
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef int (ta_init)(void **ta_state, struct table_info *ti);
|
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 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_add)(struct tentry_info *tei, void *ta_buf);
|
||||||
typedef int (ta_prepare_del)(struct tentry_info *tei, void *ta_buf);
|
typedef int (ta_prepare_del)(struct tentry_info *tei, void *ta_buf);
|
||||||
@ -69,7 +69,7 @@ typedef int ta_dump_xentry(void *ta_state, struct table_info *ti, void *e,
|
|||||||
ipfw_table_xentry *xent);
|
ipfw_table_xentry *xent);
|
||||||
|
|
||||||
struct table_algo {
|
struct table_algo {
|
||||||
char name[64];
|
char name[16];
|
||||||
int idx;
|
int idx;
|
||||||
ta_init *init;
|
ta_init *init;
|
||||||
ta_destroy *destroy;
|
ta_destroy *destroy;
|
||||||
@ -100,6 +100,11 @@ int ipfw_dump_table(struct ip_fw_chain *ch, struct sockopt *sopt,
|
|||||||
int ipfw_describe_table(struct ip_fw_chain *ch, struct sockopt *sopt,
|
int ipfw_describe_table(struct ip_fw_chain *ch, struct sockopt *sopt,
|
||||||
ip_fw3_opheader *op3, size_t valsize);
|
ip_fw3_opheader *op3, size_t valsize);
|
||||||
|
|
||||||
|
int ipfw_create_table(struct ip_fw_chain *ch, struct sockopt *sopt,
|
||||||
|
ip_fw3_opheader *op3);
|
||||||
|
int ipfw_modify_table(struct ip_fw_chain *ch, struct sockopt *sopt,
|
||||||
|
ip_fw3_opheader *op3);
|
||||||
|
|
||||||
int ipfw_destroy_table(struct ip_fw_chain *ch, struct tid_info *ti);
|
int ipfw_destroy_table(struct ip_fw_chain *ch, struct tid_info *ti);
|
||||||
int ipfw_flush_table(struct ip_fw_chain *ch, struct tid_info *ti);
|
int ipfw_flush_table(struct ip_fw_chain *ch, struct tid_info *ti);
|
||||||
int ipfw_add_table_entry(struct ip_fw_chain *ch, struct tid_info *ti,
|
int ipfw_add_table_entry(struct ip_fw_chain *ch, struct tid_info *ti,
|
||||||
|
@ -164,7 +164,7 @@ ta_lookup_radix(struct table_info *ti, void *key, uint32_t keylen,
|
|||||||
* New table
|
* New table
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
ta_init_radix(void **ta_state, struct table_info *ti)
|
ta_init_radix(void **ta_state, struct table_info *ti, char *data)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (!rn_inithead(&ti->state, OFF_LEN_INET))
|
if (!rn_inithead(&ti->state, OFF_LEN_INET))
|
||||||
@ -537,7 +537,7 @@ flush_iface_entry(struct radix_node *rn, void *arg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
ta_init_iface(void **ta_state, struct table_info *ti)
|
ta_init_iface(void **ta_state, struct table_info *ti, char *data)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (!rn_inithead(&ti->xstate, OFF_LEN_IFACE))
|
if (!rn_inithead(&ti->xstate, OFF_LEN_IFACE))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user