From owner-svn-src-projects@FreeBSD.ORG Tue Jul 29 19:49:39 2014 Return-Path: Delivered-To: svn-src-projects@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id C3129E94; Tue, 29 Jul 2014 19:49:39 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id A3D092B9D; Tue, 29 Jul 2014 19:49:39 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.9/8.14.9) with ESMTP id s6TJndNh016816; Tue, 29 Jul 2014 19:49:39 GMT (envelope-from melifaro@svn.freebsd.org) Received: (from melifaro@localhost) by svn.freebsd.org (8.14.9/8.14.9/Submit) id s6TJndEa016811; Tue, 29 Jul 2014 19:49:39 GMT (envelope-from melifaro@svn.freebsd.org) Message-Id: <201407291949.s6TJndEa016811@svn.freebsd.org> From: "Alexander V. Chernikov" Date: Tue, 29 Jul 2014 19:49:39 +0000 (UTC) To: src-committers@freebsd.org, svn-src-projects@freebsd.org Subject: svn commit: r269252 - projects/ipfw/sys/netpfil/ipfw X-SVN-Group: projects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-projects@freebsd.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: "SVN commit messages for the src " projects" tree" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 29 Jul 2014 19:49:39 -0000 Author: melifaro Date: Tue Jul 29 19:49:38 2014 New Revision: 269252 URL: http://svnweb.freebsd.org/changeset/base/269252 Log: * 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 Modified: 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_table.c ============================================================================== --- projects/ipfw/sys/netpfil/ipfw/ip_fw_table.c Tue Jul 29 19:49:27 2014 (r269251) +++ projects/ipfw/sys/netpfil/ipfw/ip_fw_table.c Tue Jul 29 19:49:38 2014 (r269252) @@ -1592,10 +1592,9 @@ find_table_algo(struct tables_config *tc /* 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); Modified: projects/ipfw/sys/netpfil/ipfw/ip_fw_table.h ============================================================================== --- projects/ipfw/sys/netpfil/ipfw/ip_fw_table.h Tue Jul 29 19:49:27 2014 (r269251) +++ projects/ipfw/sys/netpfil/ipfw/ip_fw_table.h Tue Jul 29 19:49:38 2014 (r269252) @@ -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); Modified: projects/ipfw/sys/netpfil/ipfw/ip_fw_table_algo.c ============================================================================== --- projects/ipfw/sys/netpfil/ipfw/ip_fw_table_algo.c Tue Jul 29 19:49:27 2014 (r269251) +++ projects/ipfw/sys/netpfil/ipfw/ip_fw_table_algo.c Tue Jul 29 19:49:38 2014 (r269252) @@ -514,7 +514,7 @@ ta_flush_cidr_entry(struct ip_fw_chain * 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, @@ -531,6 +531,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. * * Implementation: @@ -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 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 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 /* * 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