* Add new ipfw cidr algorihm: hash table.
Algorithm works with both IPv4 and IPv6 prefixes, /32 and /128 ranges are assumed by default. It works the following way: input IP address is masked to specified mask, hashed and searched inside hash bucket. Current implementation does not support "lookup" method and hash auto-resize. This will be changed soon. some examples: ipfw table mi_test2 create type cidr algo cidr:hash ipfw table mi_test create type cidr algo "cidr:hash masks=/30,/64" ipfw table mi_test2 info +++ table(mi_test2), set(0) +++ type: cidr, kindex: 7 valtype: number, references: 0 algorithm: cidr:hash items: 0, size: 220 ipfw table mi_test info +++ table(mi_test), set(0) +++ type: cidr, kindex: 6 valtype: number, references: 0 algorithm: cidr:hash masks=/30,/64 items: 0, size: 220 ipfw table mi_test add 10.0.0.5/30 ipfw table mi_test add 10.0.0.8/30 ipfw table mi_test add 2a02:6b8:b010::1/64 25 ipfw table mi_test list +++ table(mi_test), set(0) +++ 10.0.0.4/30 0 10.0.0.8/30 0 2a02:6b8:b010::/64 25
This commit is contained in:
parent
adea620132
commit
74b941f042
@ -1592,10 +1592,9 @@ find_table_algo(struct tables_config *tcfg, struct tid_info *ti, char *name)
|
||||
/* Search by type */
|
||||
switch (ti->type) {
|
||||
case IPFW_TABLE_CIDR:
|
||||
return (&radix_cidr);
|
||||
return (&cidr_radix);
|
||||
case IPFW_TABLE_INTERFACE:
|
||||
return (&idx_iface);
|
||||
//return (&radix_iface);
|
||||
return (&iface_idx);
|
||||
}
|
||||
|
||||
return (NULL);
|
||||
|
@ -118,7 +118,7 @@ struct table_algo {
|
||||
};
|
||||
|
||||
void ipfw_add_table_algo(struct ip_fw_chain *ch, struct table_algo *ta);
|
||||
extern struct table_algo radix_cidr, idx_iface;
|
||||
extern struct table_algo cidr_radix, iface_idx;
|
||||
|
||||
void ipfw_table_algo_init(struct ip_fw_chain *chain);
|
||||
void ipfw_table_algo_destroy(struct ip_fw_chain *chain);
|
||||
|
@ -514,7 +514,7 @@ ta_flush_cidr_entry(struct ip_fw_chain *ch, struct tentry_info *tei,
|
||||
free(tb->ent_ptr, M_IPFW_TBL);
|
||||
}
|
||||
|
||||
struct table_algo radix_cidr = {
|
||||
struct table_algo cidr_radix = {
|
||||
.name = "cidr:radix",
|
||||
.lookup = ta_lookup_radix,
|
||||
.init = ta_init_radix,
|
||||
@ -530,6 +530,686 @@ struct table_algo radix_cidr = {
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* cidr:hash cmds
|
||||
*
|
||||
*
|
||||
* ti->data:
|
||||
* [inv.mask4][inv.mask6][log2hsize4][log2hsize6]
|
||||
* [ 8][ 8[ 8][ 8]
|
||||
*
|
||||
* inv.mask4: 32 - mask
|
||||
* inv.mask6:
|
||||
* 1) _slow lookup: mask
|
||||
* 2) _aligned: (128 - mask) / 8
|
||||
* 3) _64: 8
|
||||
*/
|
||||
|
||||
struct chashentry;
|
||||
|
||||
SLIST_HEAD(chashbhead, chashentry);
|
||||
|
||||
struct chash_cfg {
|
||||
struct chashbhead *head4;
|
||||
struct chashbhead *head6;
|
||||
size_t size4;
|
||||
size_t size6;
|
||||
size_t items;
|
||||
uint8_t mask4;
|
||||
uint8_t mask6;
|
||||
};
|
||||
|
||||
struct chashentry {
|
||||
SLIST_ENTRY(chashentry) next;
|
||||
uint32_t value;
|
||||
uint32_t type;
|
||||
union {
|
||||
uint32_t a4; /* Host format */
|
||||
struct in6_addr a6; /* Network format */
|
||||
} a;
|
||||
};
|
||||
|
||||
static __inline uint32_t
|
||||
hash_ip(uint32_t addr, int hsize)
|
||||
{
|
||||
|
||||
return (addr % (hsize - 1));
|
||||
}
|
||||
|
||||
static __inline uint32_t
|
||||
hash_ip6(struct in6_addr *addr6, int hsize)
|
||||
{
|
||||
uint32_t i;
|
||||
|
||||
i = addr6->s6_addr32[0] ^ addr6->s6_addr32[1] ^
|
||||
addr6->s6_addr32[2] ^ addr6->s6_addr32[3];
|
||||
|
||||
return (i % (hsize - 1));
|
||||
}
|
||||
|
||||
|
||||
static __inline uint16_t
|
||||
hash_ip64(struct in6_addr *addr6, int hsize)
|
||||
{
|
||||
uint32_t i;
|
||||
|
||||
i = addr6->s6_addr32[0] ^ addr6->s6_addr32[1];
|
||||
|
||||
return (i % (hsize - 1));
|
||||
}
|
||||
|
||||
|
||||
static __inline uint32_t
|
||||
hash_ip6_slow(struct in6_addr *addr6, void *key, int mask, int hsize)
|
||||
{
|
||||
struct in6_addr mask6;
|
||||
|
||||
ipv6_writemask(&mask6, mask);
|
||||
memcpy(addr6, key, sizeof(struct in6_addr));
|
||||
APPLY_MASK(addr6, &mask6);
|
||||
return (hash_ip6(addr6, hsize));
|
||||
}
|
||||
|
||||
static __inline uint32_t
|
||||
hash_ip6_al(struct in6_addr *addr6, void *key, int mask, int hsize)
|
||||
{
|
||||
uint64_t *paddr;
|
||||
|
||||
paddr = (uint64_t *)addr6;
|
||||
*paddr = 0;
|
||||
*(paddr + 1) = 0;
|
||||
memcpy(addr6, key, mask);
|
||||
return (hash_ip6(addr6, hsize));
|
||||
}
|
||||
|
||||
static int
|
||||
ta_lookup_chash_slow(struct table_info *ti, void *key, uint32_t keylen,
|
||||
uint32_t *val)
|
||||
{
|
||||
struct chashbhead *head;
|
||||
struct chashentry *ent;
|
||||
uint16_t hash, hsize;
|
||||
uint8_t imask;
|
||||
|
||||
if (keylen == sizeof(in_addr_t)) {
|
||||
head = (struct chashbhead *)ti->state;
|
||||
imask = ti->data >> 24;
|
||||
hsize = 1 << ((ti->data & 0xFFFF) >> 8);
|
||||
uint32_t a;
|
||||
a = ntohl(*((in_addr_t *)key));
|
||||
a = a >> imask;
|
||||
hash = hash_ip(a, hsize);
|
||||
SLIST_FOREACH(ent, &head[hash], next) {
|
||||
if (ent->a.a4 == a) {
|
||||
*val = ent->value;
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* IPv6: worst scenario: non-round mask */
|
||||
struct in6_addr addr6;
|
||||
head = (struct chashbhead *)ti->xstate;
|
||||
imask = (ti->data & 0xFF0000) >> 16;
|
||||
hsize = 1 << (ti->data & 0xFF);
|
||||
hash = hash_ip6_slow(&addr6, key, imask, hsize);
|
||||
SLIST_FOREACH(ent, &head[hash], next) {
|
||||
if (memcmp(&ent->a.a6, &addr6, 16) == 0) {
|
||||
*val = ent->value;
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
ta_lookup_chash_aligned(struct table_info *ti, void *key, uint32_t keylen,
|
||||
uint32_t *val)
|
||||
{
|
||||
struct chashbhead *head;
|
||||
struct chashentry *ent;
|
||||
uint16_t hash, hsize;
|
||||
uint8_t imask;
|
||||
|
||||
if (keylen == sizeof(in_addr_t)) {
|
||||
head = (struct chashbhead *)ti->state;
|
||||
imask = ti->data >> 24;
|
||||
hsize = 1 << ((ti->data & 0xFFFF) >> 8);
|
||||
uint32_t a;
|
||||
a = ntohl(*((in_addr_t *)key));
|
||||
a = a >> imask;
|
||||
hash = hash_ip(a, hsize);
|
||||
SLIST_FOREACH(ent, &head[hash], next) {
|
||||
if (ent->a.a4 == a) {
|
||||
*val = ent->value;
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* IPv6: aligned to 8bit mask */
|
||||
struct in6_addr addr6;
|
||||
uint64_t *paddr, *ptmp;
|
||||
head = (struct chashbhead *)ti->xstate;
|
||||
imask = (ti->data & 0xFF0000) >> 16;
|
||||
hsize = 1 << (ti->data & 0xFF);
|
||||
|
||||
hash = hash_ip6_al(&addr6, key, imask, hsize);
|
||||
paddr = (uint64_t *)&addr6;
|
||||
SLIST_FOREACH(ent, &head[hash], next) {
|
||||
ptmp = (uint64_t *)&ent->a.a6;
|
||||
if (paddr[0] == ptmp[0] && paddr[1] == ptmp[1]) {
|
||||
*val = ent->value;
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
ta_lookup_chash_64(struct table_info *ti, void *key, uint32_t keylen,
|
||||
uint32_t *val)
|
||||
{
|
||||
struct chashbhead *head;
|
||||
struct chashentry *ent;
|
||||
uint16_t hash, hsize;
|
||||
uint8_t imask;
|
||||
|
||||
if (keylen == sizeof(in_addr_t)) {
|
||||
head = (struct chashbhead *)ti->state;
|
||||
imask = ti->data >> 24;
|
||||
hsize = 1 << ((ti->data & 0xFFFF) >> 8);
|
||||
uint32_t a;
|
||||
a = ntohl(*((in_addr_t *)key));
|
||||
a = a >> imask;
|
||||
hash = hash_ip(a, hsize);
|
||||
SLIST_FOREACH(ent, &head[hash], next) {
|
||||
if (ent->a.a4 == a) {
|
||||
*val = ent->value;
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* IPv6: /64 */
|
||||
uint64_t a6, *paddr;
|
||||
head = (struct chashbhead *)ti->xstate;
|
||||
paddr = (uint64_t *)key;
|
||||
hsize = 1 << (ti->data & 0xFF);
|
||||
a6 = *paddr;
|
||||
hash = hash_ip64((struct in6_addr *)key, hsize);
|
||||
SLIST_FOREACH(ent, &head[hash], next) {
|
||||
paddr = (uint64_t *)&ent->a.a6;
|
||||
if (a6 == *paddr) {
|
||||
*val = ent->value;
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
chash_parse_opts(struct chash_cfg *ccfg, char *data)
|
||||
{
|
||||
char *pdel, *pend, *s;
|
||||
int mask4, mask6;
|
||||
|
||||
mask4 = ccfg->mask4;
|
||||
mask6 = ccfg->mask6;
|
||||
|
||||
if (data == NULL)
|
||||
return (0);
|
||||
if ((pdel = strchr(data, ' ')) == NULL)
|
||||
return (0);
|
||||
while (*pdel == ' ')
|
||||
pdel++;
|
||||
if (strncmp(pdel, "masks=", 6) != 0)
|
||||
return (EINVAL);
|
||||
if ((s = strchr(pdel, ' ')) != NULL)
|
||||
*s++ = '\0';
|
||||
|
||||
pdel += 6;
|
||||
/* Need /XX[,/YY] */
|
||||
if (*pdel++ != '/')
|
||||
return (EINVAL);
|
||||
mask4 = strtol(pdel, &pend, 10);
|
||||
if (*pend == ',') {
|
||||
/* ,/YY */
|
||||
pdel = pend + 1;
|
||||
if (*pdel++ != '/')
|
||||
return (EINVAL);
|
||||
mask6 = strtol(pdel, &pend, 10);
|
||||
if (*pend != '\0')
|
||||
return (EINVAL);
|
||||
} else if (*pend != '\0')
|
||||
return (EINVAL);
|
||||
|
||||
if (mask4 < 0 || mask4 > 32 || mask6 < 0 || mask6 > 128)
|
||||
return (EINVAL);
|
||||
|
||||
ccfg->mask4 = mask4;
|
||||
ccfg->mask6 = mask6;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
ta_print_chash_config(void *ta_state, struct table_info *ti, char *buf,
|
||||
size_t bufsize)
|
||||
{
|
||||
struct chash_cfg *ccfg;
|
||||
|
||||
ccfg = (struct chash_cfg *)ta_state;
|
||||
|
||||
if (ccfg->mask4 != 32 || ccfg->mask6 != 128)
|
||||
snprintf(buf, bufsize, "%s masks=/%d,/%d", "cidr:hash",
|
||||
ccfg->mask4, ccfg->mask6);
|
||||
else
|
||||
snprintf(buf, bufsize, "%s", "cidr:hash");
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* New table.
|
||||
* We assume 'data' to be either NULL or the following format:
|
||||
* 'cidr:hash [masks=/32[,/128]]'
|
||||
*/
|
||||
static int
|
||||
ta_init_chash(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti,
|
||||
char *data)
|
||||
{
|
||||
int error, i;
|
||||
int v4, v6;
|
||||
struct chash_cfg *ccfg;
|
||||
|
||||
ccfg = malloc(sizeof(struct chash_cfg), M_IPFW, M_WAITOK | M_ZERO);
|
||||
|
||||
ccfg->mask4 = 32;
|
||||
ccfg->mask6 = 128;
|
||||
|
||||
if ((error = chash_parse_opts(ccfg, data)) != 0) {
|
||||
free(ccfg, M_IPFW);
|
||||
return (error);
|
||||
}
|
||||
|
||||
v4 = 7;
|
||||
v6 = 7;
|
||||
ccfg->size4 = 1 << v4;
|
||||
ccfg->size6 = 1 << v6;
|
||||
|
||||
ccfg->head4 = malloc(sizeof(struct chashbhead) * ccfg->size4, M_IPFW,
|
||||
M_WAITOK | M_ZERO);
|
||||
ccfg->head6 = malloc(sizeof(struct chashbhead) * ccfg->size6, M_IPFW,
|
||||
M_WAITOK | M_ZERO);
|
||||
for (i = 0; i < ccfg->size4; i++)
|
||||
SLIST_INIT(&ccfg->head4[i]);
|
||||
for (i = 0; i < ccfg->size6; i++)
|
||||
SLIST_INIT(&ccfg->head6[i]);
|
||||
|
||||
|
||||
*ta_state = ccfg;
|
||||
ti->state = ccfg->head4;
|
||||
ti->xstate = ccfg->head6;
|
||||
|
||||
/* Store data depending on v6 mask length */
|
||||
if (ccfg->mask6 == 64) {
|
||||
ti->data = (32 - ccfg->mask4) << 24 | (128 - ccfg->mask6) << 16 |
|
||||
v4 << 8 | v6;
|
||||
ti->lookup = ta_lookup_chash_64;
|
||||
} else if ((ccfg->mask6 % 8) == 0) {
|
||||
ti->data = (32 - ccfg->mask4) << 24 |
|
||||
ccfg->mask6 << 13 | v4 << 8 | v6;
|
||||
ti->lookup = ta_lookup_chash_aligned;
|
||||
} else {
|
||||
/* don't do that! */
|
||||
ti->data = (32 - ccfg->mask4) << 24 |
|
||||
ccfg->mask6 << 16 | v4 << 8 | v6;
|
||||
ti->lookup = ta_lookup_chash_slow;
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
ta_destroy_chash(void *ta_state, struct table_info *ti)
|
||||
{
|
||||
struct chash_cfg *ccfg;
|
||||
struct chashentry *ent, *ent_next;
|
||||
int i;
|
||||
|
||||
ccfg = (struct chash_cfg *)ta_state;
|
||||
|
||||
for (i = 0; i < ccfg->size4; i++)
|
||||
SLIST_FOREACH_SAFE(ent, &ccfg->head4[i], next, ent_next)
|
||||
free(ent, M_IPFW_TBL);
|
||||
|
||||
for (i = 0; i < ccfg->size6; i++)
|
||||
SLIST_FOREACH_SAFE(ent, &ccfg->head6[i], next, ent_next)
|
||||
free(ent, M_IPFW_TBL);
|
||||
|
||||
free(ccfg->head4, M_IPFW);
|
||||
free(ccfg->head6, M_IPFW);
|
||||
}
|
||||
|
||||
static int
|
||||
ta_dump_chash_tentry(void *ta_state, struct table_info *ti, void *e,
|
||||
ipfw_obj_tentry *tent)
|
||||
{
|
||||
struct chash_cfg *ccfg;
|
||||
struct chashentry *ent;
|
||||
|
||||
ccfg = (struct chash_cfg *)ta_state;
|
||||
ent = (struct chashentry *)e;
|
||||
|
||||
if (ent->type == AF_INET) {
|
||||
tent->k.addr.s_addr = htonl(ent->a.a4 << (32 - ccfg->mask4));
|
||||
tent->masklen = ccfg->mask4;
|
||||
tent->subtype = AF_INET;
|
||||
tent->value = ent->value;
|
||||
#ifdef INET6
|
||||
} else {
|
||||
memcpy(&tent->k, &ent->a.a6, sizeof(struct in6_addr));
|
||||
tent->masklen = ccfg->mask6;
|
||||
tent->subtype = AF_INET6;
|
||||
tent->value = ent->value;
|
||||
#endif
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
ta_find_chash_tentry(void *ta_state, struct table_info *ti, void *key,
|
||||
uint32_t keylen, ipfw_obj_tentry *tent)
|
||||
{
|
||||
#if 0
|
||||
struct radix_node_head *rnh;
|
||||
void *e;
|
||||
|
||||
e = NULL;
|
||||
if (keylen == sizeof(in_addr_t)) {
|
||||
struct sockaddr_in sa;
|
||||
KEY_LEN(sa) = KEY_LEN_INET;
|
||||
sa.sin_addr.s_addr = *((in_addr_t *)key);
|
||||
rnh = (struct radix_node_head *)ti->state;
|
||||
e = rnh->rnh_matchaddr(&sa, rnh);
|
||||
} else {
|
||||
struct sa_in6 sa6;
|
||||
KEY_LEN(sa6) = KEY_LEN_INET6;
|
||||
memcpy(&sa6.sin6_addr, key, sizeof(struct in6_addr));
|
||||
rnh = (struct radix_node_head *)ti->xstate;
|
||||
e = rnh->rnh_matchaddr(&sa6, rnh);
|
||||
}
|
||||
|
||||
if (e != NULL) {
|
||||
ta_dump_radix_tentry(ta_state, ti, e, tent);
|
||||
return (0);
|
||||
}
|
||||
#endif
|
||||
return (ENOENT);
|
||||
}
|
||||
|
||||
static void
|
||||
ta_foreach_chash(void *ta_state, struct table_info *ti, ta_foreach_f *f,
|
||||
void *arg)
|
||||
{
|
||||
struct chash_cfg *ccfg;
|
||||
struct chashentry *ent, *ent_next;
|
||||
int i;
|
||||
|
||||
ccfg = (struct chash_cfg *)ta_state;
|
||||
|
||||
for (i = 0; i < ccfg->size4; i++)
|
||||
SLIST_FOREACH_SAFE(ent, &ccfg->head4[i], next, ent_next)
|
||||
f(ent, arg);
|
||||
|
||||
for (i = 0; i < ccfg->size6; i++)
|
||||
SLIST_FOREACH_SAFE(ent, &ccfg->head6[i], next, ent_next)
|
||||
f(ent, arg);
|
||||
}
|
||||
|
||||
|
||||
struct ta_buf_chash
|
||||
{
|
||||
void *ent_ptr;
|
||||
int type;
|
||||
union {
|
||||
uint32_t a4;
|
||||
struct in6_addr a6;
|
||||
} a;
|
||||
};
|
||||
|
||||
static int
|
||||
ta_prepare_add_chash(struct ip_fw_chain *ch, struct tentry_info *tei,
|
||||
void *ta_buf)
|
||||
{
|
||||
struct ta_buf_chash *tb;
|
||||
struct chashentry *ent;
|
||||
int mlen;
|
||||
struct in6_addr mask6;
|
||||
|
||||
tb = (struct ta_buf_chash *)ta_buf;
|
||||
memset(tb, 0, sizeof(struct ta_buf_chash));
|
||||
|
||||
mlen = tei->masklen;
|
||||
|
||||
if (tei->subtype == AF_INET) {
|
||||
#ifdef INET
|
||||
if (mlen > 32)
|
||||
return (EINVAL);
|
||||
ent = malloc(sizeof(*ent), M_IPFW_TBL, M_WAITOK | M_ZERO);
|
||||
ent->value = tei->value;
|
||||
ent->type = AF_INET;
|
||||
|
||||
/* Calculate mask */
|
||||
ent->a.a4 = ntohl(*((in_addr_t *)tei->paddr)) >> (32 - mlen);
|
||||
tb->ent_ptr = ent;
|
||||
#endif
|
||||
#ifdef INET6
|
||||
} else if (tei->subtype == AF_INET6) {
|
||||
/* IPv6 case */
|
||||
if (mlen > 128)
|
||||
return (EINVAL);
|
||||
ent = malloc(sizeof(*ent), M_IPFW_TBL, M_WAITOK | M_ZERO);
|
||||
ent->value = tei->value;
|
||||
ent->type = AF_INET6;
|
||||
|
||||
ipv6_writemask(&mask6, mlen);
|
||||
memcpy(&ent->a.a6, tei->paddr, sizeof(struct in6_addr));
|
||||
APPLY_MASK(&ent->a.a6, &mask6);
|
||||
tb->ent_ptr = ent;
|
||||
#endif
|
||||
} else {
|
||||
/* Unknown CIDR type */
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
struct chash_cfg *ccfg;
|
||||
struct chashbhead *head;
|
||||
struct chashentry *ent, *tmp;
|
||||
struct ta_buf_chash *tb;
|
||||
int exists;
|
||||
uint32_t hash;
|
||||
|
||||
ccfg = (struct chash_cfg *)ta_state;
|
||||
tb = (struct ta_buf_chash *)ta_buf;
|
||||
ent = (struct chashentry *)tb->ent_ptr;
|
||||
hash = 0;
|
||||
exists = 0;
|
||||
|
||||
if (tei->subtype == AF_INET) {
|
||||
if (tei->masklen != ccfg->mask4)
|
||||
return (EINVAL);
|
||||
head = ccfg->head4;
|
||||
hash = hash_ip(ent->a.a4, ccfg->size4);
|
||||
/* Check for existence */
|
||||
SLIST_FOREACH(tmp, &head[hash], next) {
|
||||
if (tmp->a.a4 == ent->a.a4) {
|
||||
exists = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (tei->masklen != ccfg->mask6)
|
||||
return (EINVAL);
|
||||
head = ccfg->head6;
|
||||
if (tei->masklen == 64)
|
||||
hash = hash_ip64(&ent->a.a6, ccfg->size6);
|
||||
else
|
||||
hash = hash_ip6(&ent->a.a6, ccfg->size6);
|
||||
/* Check for existence */
|
||||
SLIST_FOREACH(tmp, &head[hash], next) {
|
||||
if (memcmp(&tmp->a.a6, &ent->a.a6, 16)) {
|
||||
exists = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (exists == 1) {
|
||||
if ((tei->flags & TEI_FLAGS_UPDATE) == 0)
|
||||
return (EEXIST);
|
||||
/* Record already exists. Update value if we're asked to */
|
||||
tmp->value = tei->value;
|
||||
/* Indicate that update has happened instead of addition */
|
||||
tei->flags |= TEI_FLAGS_UPDATED;
|
||||
*pnum = 0;
|
||||
} else {
|
||||
SLIST_INSERT_HEAD(&head[hash], ent, next);
|
||||
tb->ent_ptr = NULL;
|
||||
*pnum = 1;
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
ta_prepare_del_chash(struct ip_fw_chain *ch, struct tentry_info *tei,
|
||||
void *ta_buf)
|
||||
{
|
||||
struct ta_buf_chash *tb;
|
||||
int mlen;
|
||||
struct in6_addr mask6;
|
||||
|
||||
tb = (struct ta_buf_chash *)ta_buf;
|
||||
memset(tb, 0, sizeof(struct ta_buf_chash));
|
||||
|
||||
mlen = tei->masklen;
|
||||
|
||||
if (tei->subtype == AF_INET) {
|
||||
#ifdef INET
|
||||
if (mlen > 32)
|
||||
return (EINVAL);
|
||||
tb->type = AF_INET;
|
||||
|
||||
/* Calculate masked address */
|
||||
tb->a.a4 = ntohl(*((in_addr_t *)tei->paddr)) >> (32 - mlen);
|
||||
#endif
|
||||
#ifdef INET6
|
||||
} else if (tei->subtype == AF_INET6) {
|
||||
/* IPv6 case */
|
||||
if (mlen > 128)
|
||||
return (EINVAL);
|
||||
tb->type = AF_INET6;
|
||||
|
||||
ipv6_writemask(&mask6, mlen);
|
||||
memcpy(&tb->a.a6, tei->paddr, sizeof(struct in6_addr));
|
||||
APPLY_MASK(&tb->a.a6, &mask6);
|
||||
#endif
|
||||
} else {
|
||||
/* Unknown CIDR type */
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
struct chash_cfg *ccfg;
|
||||
struct chashbhead *head;
|
||||
struct chashentry *ent, *tmp_next;
|
||||
struct ta_buf_chash *tb;
|
||||
uint32_t hash;
|
||||
|
||||
ccfg = (struct chash_cfg *)ta_state;
|
||||
tb = (struct ta_buf_chash *)ta_buf;
|
||||
|
||||
if (tei->subtype == AF_INET) {
|
||||
if (tei->masklen != ccfg->mask4)
|
||||
return (EINVAL);
|
||||
head = ccfg->head4;
|
||||
hash = hash_ip(tb->a.a4, ccfg->size4);
|
||||
|
||||
SLIST_FOREACH_SAFE(ent, &head[hash], next, tmp_next) {
|
||||
if (ent->a.a4 == tb->a.a4) {
|
||||
SLIST_REMOVE(&head[hash], ent, chashentry,next);
|
||||
*pnum = 1;
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (tei->masklen != ccfg->mask6)
|
||||
return (EINVAL);
|
||||
head = ccfg->head6;
|
||||
if (tei->masklen == 64)
|
||||
hash = hash_ip64(&tb->a.a6, ccfg->size6);
|
||||
else
|
||||
hash = hash_ip6(&tb->a.a6, ccfg->size6);
|
||||
|
||||
SLIST_FOREACH_SAFE(ent, &head[hash], next, tmp_next) {
|
||||
if (memcmp(&ent->a.a6, &tb->a.a6, 16)) {
|
||||
SLIST_REMOVE(&head[hash], ent, chashentry,next);
|
||||
*pnum = 1;
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (ENOENT);
|
||||
}
|
||||
|
||||
static void
|
||||
ta_flush_chash_entry(struct ip_fw_chain *ch, struct tentry_info *tei,
|
||||
void *ta_buf)
|
||||
{
|
||||
struct ta_buf_chash *tb;
|
||||
|
||||
tb = (struct ta_buf_chash *)ta_buf;
|
||||
|
||||
if (tb->ent_ptr != NULL)
|
||||
free(tb->ent_ptr, M_IPFW_TBL);
|
||||
}
|
||||
|
||||
struct table_algo cidr_hash = {
|
||||
.name = "cidr:hash",
|
||||
.lookup = ta_lookup_chash_slow,
|
||||
.init = ta_init_chash,
|
||||
.destroy = ta_destroy_chash,
|
||||
.prepare_add = ta_prepare_add_chash,
|
||||
.prepare_del = ta_prepare_del_chash,
|
||||
.add = ta_add_chash,
|
||||
.del = ta_del_chash,
|
||||
.flush_entry = ta_flush_chash_entry,
|
||||
.foreach = ta_foreach_chash,
|
||||
.dump_tentry = ta_dump_chash_tentry,
|
||||
.find_tentry = ta_find_chash_tentry,
|
||||
.print_config = ta_print_chash_config,
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Iface table cmds.
|
||||
*
|
||||
@ -560,7 +1240,6 @@ struct ifentry {
|
||||
struct named_object no;
|
||||
struct ipfw_ifc ic;
|
||||
struct iftable_cfg *icfg;
|
||||
TAILQ_ENTRY(ifentry) next;
|
||||
uint32_t value;
|
||||
int linked;
|
||||
};
|
||||
@ -788,7 +1467,7 @@ ta_prepare_add_ifidx(struct ip_fw_chain *ch, struct tentry_info *tei,
|
||||
struct ifentry *ife;
|
||||
|
||||
tb = (struct ta_buf_ifidx *)ta_buf;
|
||||
memset(tb, 0, sizeof(struct ta_buf_cidr));
|
||||
memset(tb, 0, sizeof(struct ta_buf_ifidx));
|
||||
|
||||
/* Check if string is terminated */
|
||||
ifname = (char *)tei->paddr;
|
||||
@ -877,11 +1556,11 @@ static int
|
||||
ta_prepare_del_ifidx(struct ip_fw_chain *ch, struct tentry_info *tei,
|
||||
void *ta_buf)
|
||||
{
|
||||
struct ta_buf_iface *tb;
|
||||
struct ta_buf_ifidx *tb;
|
||||
char *ifname;
|
||||
|
||||
tb = (struct ta_buf_iface *)ta_buf;
|
||||
memset(tb, 0, sizeof(struct ta_buf_cidr));
|
||||
tb = (struct ta_buf_ifidx *)ta_buf;
|
||||
memset(tb, 0, sizeof(struct ta_buf_ifidx));
|
||||
|
||||
/* Check if string is terminated */
|
||||
ifname = (char *)tei->paddr;
|
||||
@ -1167,7 +1846,7 @@ ta_foreach_ifidx(void *ta_state, struct table_info *ti, ta_foreach_f *f,
|
||||
ipfw_objhash_foreach(icfg->ii, foreach_ifidx, &wa);
|
||||
}
|
||||
|
||||
struct table_algo idx_iface = {
|
||||
struct table_algo iface_idx = {
|
||||
.name = "iface:array",
|
||||
.lookup = ta_lookup_ifidx,
|
||||
.init = ta_init_ifidx,
|
||||
@ -1193,8 +1872,9 @@ ipfw_table_algo_init(struct ip_fw_chain *chain)
|
||||
/*
|
||||
* Register all algorithms presented here.
|
||||
*/
|
||||
ipfw_add_table_algo(chain, &radix_cidr);
|
||||
ipfw_add_table_algo(chain, &idx_iface);
|
||||
ipfw_add_table_algo(chain, &cidr_radix);
|
||||
ipfw_add_table_algo(chain, &cidr_hash);
|
||||
ipfw_add_table_algo(chain, &iface_idx);
|
||||
}
|
||||
|
||||
void
|
||||
|
Loading…
x
Reference in New Issue
Block a user