19f7d47b0SAlexander V. Chernikov /*- 29f7d47b0SAlexander V. Chernikov * Copyright (c) 2004 Ruslan Ermilov and Vsevolod Lobko. 39f7d47b0SAlexander V. Chernikov * 49f7d47b0SAlexander V. Chernikov * Redistribution and use in source and binary forms, with or without 59f7d47b0SAlexander V. Chernikov * modification, are permitted provided that the following conditions 69f7d47b0SAlexander V. Chernikov * are met: 79f7d47b0SAlexander V. Chernikov * 1. Redistributions of source code must retain the above copyright 89f7d47b0SAlexander V. Chernikov * notice, this list of conditions and the following disclaimer. 99f7d47b0SAlexander V. Chernikov * 2. Redistributions in binary form must reproduce the above copyright 109f7d47b0SAlexander V. Chernikov * notice, this list of conditions and the following disclaimer in the 119f7d47b0SAlexander V. Chernikov * documentation and/or other materials provided with the distribution. 129f7d47b0SAlexander V. Chernikov * 139f7d47b0SAlexander V. Chernikov * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 149f7d47b0SAlexander V. Chernikov * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 159f7d47b0SAlexander V. Chernikov * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 169f7d47b0SAlexander V. Chernikov * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 179f7d47b0SAlexander V. Chernikov * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 189f7d47b0SAlexander V. Chernikov * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 199f7d47b0SAlexander V. Chernikov * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 209f7d47b0SAlexander V. Chernikov * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 219f7d47b0SAlexander V. Chernikov * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 229f7d47b0SAlexander V. Chernikov * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 239f7d47b0SAlexander V. Chernikov * SUCH DAMAGE. 249f7d47b0SAlexander V. Chernikov */ 259f7d47b0SAlexander V. Chernikov 269f7d47b0SAlexander V. Chernikov #include <sys/cdefs.h> 279f7d47b0SAlexander V. Chernikov __FBSDID("$FreeBSD: projects/ipfw/sys/netpfil/ipfw/ip_fw_table.c 267384 2014-06-12 09:59:11Z melifaro $"); 289f7d47b0SAlexander V. Chernikov 299f7d47b0SAlexander V. Chernikov /* 309f7d47b0SAlexander V. Chernikov * Lookup table algorithms. 319f7d47b0SAlexander V. Chernikov * 329f7d47b0SAlexander V. Chernikov */ 339f7d47b0SAlexander V. Chernikov 349f7d47b0SAlexander V. Chernikov #include "opt_ipfw.h" 359f7d47b0SAlexander V. Chernikov #include "opt_inet.h" 369f7d47b0SAlexander V. Chernikov #ifndef INET 379f7d47b0SAlexander V. Chernikov #error IPFIREWALL requires INET. 389f7d47b0SAlexander V. Chernikov #endif /* INET */ 399f7d47b0SAlexander V. Chernikov #include "opt_inet6.h" 409f7d47b0SAlexander V. Chernikov 419f7d47b0SAlexander V. Chernikov #include <sys/param.h> 429f7d47b0SAlexander V. Chernikov #include <sys/systm.h> 439f7d47b0SAlexander V. Chernikov #include <sys/malloc.h> 449f7d47b0SAlexander V. Chernikov #include <sys/kernel.h> 459f7d47b0SAlexander V. Chernikov #include <sys/lock.h> 469f7d47b0SAlexander V. Chernikov #include <sys/rwlock.h> 479f7d47b0SAlexander V. Chernikov #include <sys/socket.h> 489f7d47b0SAlexander V. Chernikov #include <sys/queue.h> 499f7d47b0SAlexander V. Chernikov #include <net/if.h> /* ip_fw.h requires IFNAMSIZ */ 509f7d47b0SAlexander V. Chernikov #include <net/radix.h> 519f7d47b0SAlexander V. Chernikov 529f7d47b0SAlexander V. Chernikov #include <netinet/in.h> 539f7d47b0SAlexander V. Chernikov #include <netinet/ip_var.h> /* struct ipfw_rule_ref */ 549f7d47b0SAlexander V. Chernikov #include <netinet/ip_fw.h> 559f7d47b0SAlexander V. Chernikov 569f7d47b0SAlexander V. Chernikov #include <netpfil/ipfw/ip_fw_private.h> 57ea761a5dSAlexander V. Chernikov #include <netpfil/ipfw/ip_fw_table.h> 589f7d47b0SAlexander V. Chernikov 599f7d47b0SAlexander V. Chernikov static MALLOC_DEFINE(M_IPFW_TBL, "ipfw_tbl", "IpFw tables"); 609f7d47b0SAlexander V. Chernikov 610bce0c23SAlexander V. Chernikov /* 620bce0c23SAlexander V. Chernikov * Utility structures/functions common to more than one algo 630bce0c23SAlexander V. Chernikov */ 640bce0c23SAlexander V. Chernikov 650bce0c23SAlexander V. Chernikov struct mod_item { 660bce0c23SAlexander V. Chernikov void *main_ptr; 670bce0c23SAlexander V. Chernikov size_t size; 680bce0c23SAlexander V. Chernikov void *main_ptr6; 690bce0c23SAlexander V. Chernikov size_t size6; 700bce0c23SAlexander V. Chernikov }; 710bce0c23SAlexander V. Chernikov 7268394ec8SAlexander V. Chernikov static int badd(const void *key, void *item, void *base, size_t nmemb, 7368394ec8SAlexander V. Chernikov size_t size, int (*compar) (const void *, const void *)); 7468394ec8SAlexander V. Chernikov static int bdel(const void *key, void *base, size_t nmemb, size_t size, 7568394ec8SAlexander V. Chernikov int (*compar) (const void *, const void *)); 7668394ec8SAlexander V. Chernikov 7768394ec8SAlexander V. Chernikov 7868394ec8SAlexander V. Chernikov /* 7968394ec8SAlexander V. Chernikov * CIDR implementation using radix 8068394ec8SAlexander V. Chernikov * 8168394ec8SAlexander V. Chernikov */ 8268394ec8SAlexander V. Chernikov 839f7d47b0SAlexander V. Chernikov /* 849f7d47b0SAlexander V. Chernikov * The radix code expects addr and mask to be array of bytes, 859f7d47b0SAlexander V. Chernikov * with the first byte being the length of the array. rn_inithead 869f7d47b0SAlexander V. Chernikov * is called with the offset in bits of the lookup key within the 879f7d47b0SAlexander V. Chernikov * array. If we use a sockaddr_in as the underlying type, 889f7d47b0SAlexander V. Chernikov * sin_len is conveniently located at offset 0, sin_addr is at 899f7d47b0SAlexander V. Chernikov * offset 4 and normally aligned. 909f7d47b0SAlexander V. Chernikov * But for portability, let's avoid assumption and make the code explicit 919f7d47b0SAlexander V. Chernikov */ 929f7d47b0SAlexander V. Chernikov #define KEY_LEN(v) *((uint8_t *)&(v)) 939f7d47b0SAlexander V. Chernikov /* 949f7d47b0SAlexander V. Chernikov * Do not require radix to compare more than actual IPv4/IPv6 address 959f7d47b0SAlexander V. Chernikov */ 969f7d47b0SAlexander V. Chernikov #define KEY_LEN_INET (offsetof(struct sockaddr_in, sin_addr) + sizeof(in_addr_t)) 97e0a8b9eeSAlexander V. Chernikov #define KEY_LEN_INET6 (offsetof(struct sa_in6, sin6_addr) + sizeof(struct in6_addr)) 989f7d47b0SAlexander V. Chernikov 999f7d47b0SAlexander V. Chernikov #define OFF_LEN_INET (8 * offsetof(struct sockaddr_in, sin_addr)) 100e0a8b9eeSAlexander V. Chernikov #define OFF_LEN_INET6 (8 * offsetof(struct sa_in6, sin6_addr)) 1019f7d47b0SAlexander V. Chernikov 102e0a8b9eeSAlexander V. Chernikov struct radix_cidr_entry { 1039f7d47b0SAlexander V. Chernikov struct radix_node rn[2]; 104e0a8b9eeSAlexander V. Chernikov struct sockaddr_in addr; 105e0a8b9eeSAlexander V. Chernikov uint32_t value; 106e0a8b9eeSAlexander V. Chernikov uint8_t masklen; 107e0a8b9eeSAlexander V. Chernikov }; 108e0a8b9eeSAlexander V. Chernikov 109e0a8b9eeSAlexander V. Chernikov struct sa_in6 { 110e0a8b9eeSAlexander V. Chernikov uint8_t sin6_len; 111e0a8b9eeSAlexander V. Chernikov uint8_t sin6_family; 112e0a8b9eeSAlexander V. Chernikov uint8_t pad[2]; 113e0a8b9eeSAlexander V. Chernikov struct in6_addr sin6_addr; 114e0a8b9eeSAlexander V. Chernikov }; 115e0a8b9eeSAlexander V. Chernikov 116e0a8b9eeSAlexander V. Chernikov struct radix_cidr_xentry { 117e0a8b9eeSAlexander V. Chernikov struct radix_node rn[2]; 118e0a8b9eeSAlexander V. Chernikov struct sa_in6 addr6; 119e0a8b9eeSAlexander V. Chernikov uint32_t value; 120e0a8b9eeSAlexander V. Chernikov uint8_t masklen; 1219f7d47b0SAlexander V. Chernikov }; 1229f7d47b0SAlexander V. Chernikov 1235f379342SAlexander V. Chernikov struct radix_cfg { 1245f379342SAlexander V. Chernikov struct radix_node_head *head4; 1255f379342SAlexander V. Chernikov struct radix_node_head *head6; 1265f379342SAlexander V. Chernikov size_t count4; 1275f379342SAlexander V. Chernikov size_t count6; 1285f379342SAlexander V. Chernikov }; 1295f379342SAlexander V. Chernikov 1300bce0c23SAlexander V. Chernikov struct ta_buf_cidr 1310bce0c23SAlexander V. Chernikov { 1320bce0c23SAlexander V. Chernikov void *ent_ptr; 1330bce0c23SAlexander V. Chernikov struct sockaddr *addr_ptr; 1340bce0c23SAlexander V. Chernikov struct sockaddr *mask_ptr; 1350bce0c23SAlexander V. Chernikov union { 1360bce0c23SAlexander V. Chernikov struct { 1370bce0c23SAlexander V. Chernikov struct sockaddr_in sa; 1380bce0c23SAlexander V. Chernikov struct sockaddr_in ma; 1390bce0c23SAlexander V. Chernikov } a4; 1400bce0c23SAlexander V. Chernikov struct { 1410bce0c23SAlexander V. Chernikov struct sa_in6 sa; 1420bce0c23SAlexander V. Chernikov struct sa_in6 ma; 1430bce0c23SAlexander V. Chernikov } a6; 1440bce0c23SAlexander V. Chernikov } addr; 1450bce0c23SAlexander V. Chernikov }; 1460bce0c23SAlexander V. Chernikov 1479f7d47b0SAlexander V. Chernikov static int 1489f7d47b0SAlexander V. Chernikov ta_lookup_radix(struct table_info *ti, void *key, uint32_t keylen, 1499f7d47b0SAlexander V. Chernikov uint32_t *val) 1509f7d47b0SAlexander V. Chernikov { 1519f7d47b0SAlexander V. Chernikov struct radix_node_head *rnh; 1529f7d47b0SAlexander V. Chernikov 1539f7d47b0SAlexander V. Chernikov if (keylen == sizeof(in_addr_t)) { 154e0a8b9eeSAlexander V. Chernikov struct radix_cidr_entry *ent; 1559f7d47b0SAlexander V. Chernikov struct sockaddr_in sa; 1569f7d47b0SAlexander V. Chernikov KEY_LEN(sa) = KEY_LEN_INET; 1579f7d47b0SAlexander V. Chernikov sa.sin_addr.s_addr = *((in_addr_t *)key); 1589f7d47b0SAlexander V. Chernikov rnh = (struct radix_node_head *)ti->state; 159e0a8b9eeSAlexander V. Chernikov ent = (struct radix_cidr_entry *)(rnh->rnh_matchaddr(&sa, rnh)); 1609f7d47b0SAlexander V. Chernikov if (ent != NULL) { 1619f7d47b0SAlexander V. Chernikov *val = ent->value; 1629f7d47b0SAlexander V. Chernikov return (1); 1639f7d47b0SAlexander V. Chernikov } 1649f7d47b0SAlexander V. Chernikov } else { 165e0a8b9eeSAlexander V. Chernikov struct radix_cidr_xentry *xent; 166e0a8b9eeSAlexander V. Chernikov struct sa_in6 sa6; 1679f7d47b0SAlexander V. Chernikov KEY_LEN(sa6) = KEY_LEN_INET6; 1689f7d47b0SAlexander V. Chernikov memcpy(&sa6.sin6_addr, key, sizeof(struct in6_addr)); 1699f7d47b0SAlexander V. Chernikov rnh = (struct radix_node_head *)ti->xstate; 170e0a8b9eeSAlexander V. Chernikov xent = (struct radix_cidr_xentry *)(rnh->rnh_matchaddr(&sa6, rnh)); 1719f7d47b0SAlexander V. Chernikov if (xent != NULL) { 1729f7d47b0SAlexander V. Chernikov *val = xent->value; 1739f7d47b0SAlexander V. Chernikov return (1); 1749f7d47b0SAlexander V. Chernikov } 1759f7d47b0SAlexander V. Chernikov } 1769f7d47b0SAlexander V. Chernikov 1779f7d47b0SAlexander V. Chernikov return (0); 1789f7d47b0SAlexander V. Chernikov } 1799f7d47b0SAlexander V. Chernikov 1809f7d47b0SAlexander V. Chernikov /* 1819f7d47b0SAlexander V. Chernikov * New table 1829f7d47b0SAlexander V. Chernikov */ 1839f7d47b0SAlexander V. Chernikov static int 18468394ec8SAlexander V. Chernikov ta_init_radix(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti, 185914bffb6SAlexander V. Chernikov char *data, uint8_t tflags) 1869f7d47b0SAlexander V. Chernikov { 1875f379342SAlexander V. Chernikov struct radix_cfg *cfg; 1889f7d47b0SAlexander V. Chernikov 1899f7d47b0SAlexander V. Chernikov if (!rn_inithead(&ti->state, OFF_LEN_INET)) 1909f7d47b0SAlexander V. Chernikov return (ENOMEM); 1919f7d47b0SAlexander V. Chernikov if (!rn_inithead(&ti->xstate, OFF_LEN_INET6)) { 1929f7d47b0SAlexander V. Chernikov rn_detachhead(&ti->state); 1939f7d47b0SAlexander V. Chernikov return (ENOMEM); 1949f7d47b0SAlexander V. Chernikov } 1959f7d47b0SAlexander V. Chernikov 1965f379342SAlexander V. Chernikov cfg = malloc(sizeof(struct radix_cfg), M_IPFW, M_WAITOK | M_ZERO); 1975f379342SAlexander V. Chernikov 1985f379342SAlexander V. Chernikov *ta_state = cfg; 1999f7d47b0SAlexander V. Chernikov ti->lookup = ta_lookup_radix; 2009f7d47b0SAlexander V. Chernikov 2019f7d47b0SAlexander V. Chernikov return (0); 2029f7d47b0SAlexander V. Chernikov } 2039f7d47b0SAlexander V. Chernikov 2049f7d47b0SAlexander V. Chernikov static int 205a399f8beSAlexander V. Chernikov flush_radix_entry(struct radix_node *rn, void *arg) 2069f7d47b0SAlexander V. Chernikov { 2079f7d47b0SAlexander V. Chernikov struct radix_node_head * const rnh = arg; 208e0a8b9eeSAlexander V. Chernikov struct radix_cidr_entry *ent; 2099f7d47b0SAlexander V. Chernikov 210e0a8b9eeSAlexander V. Chernikov ent = (struct radix_cidr_entry *) 2119f7d47b0SAlexander V. Chernikov rnh->rnh_deladdr(rn->rn_key, rn->rn_mask, rnh); 2129f7d47b0SAlexander V. Chernikov if (ent != NULL) 2139f7d47b0SAlexander V. Chernikov free(ent, M_IPFW_TBL); 2149f7d47b0SAlexander V. Chernikov return (0); 2159f7d47b0SAlexander V. Chernikov } 2169f7d47b0SAlexander V. Chernikov 2179f7d47b0SAlexander V. Chernikov static void 2189f7d47b0SAlexander V. Chernikov ta_destroy_radix(void *ta_state, struct table_info *ti) 2199f7d47b0SAlexander V. Chernikov { 2205f379342SAlexander V. Chernikov struct radix_cfg *cfg; 2219f7d47b0SAlexander V. Chernikov struct radix_node_head *rnh; 2229f7d47b0SAlexander V. Chernikov 2235f379342SAlexander V. Chernikov cfg = (struct radix_cfg *)ta_state; 2245f379342SAlexander V. Chernikov 2259f7d47b0SAlexander V. Chernikov rnh = (struct radix_node_head *)(ti->state); 226a399f8beSAlexander V. Chernikov rnh->rnh_walktree(rnh, flush_radix_entry, rnh); 2279f7d47b0SAlexander V. Chernikov rn_detachhead(&ti->state); 2289f7d47b0SAlexander V. Chernikov 2299f7d47b0SAlexander V. Chernikov rnh = (struct radix_node_head *)(ti->xstate); 230a399f8beSAlexander V. Chernikov rnh->rnh_walktree(rnh, flush_radix_entry, rnh); 2319f7d47b0SAlexander V. Chernikov rn_detachhead(&ti->xstate); 2325f379342SAlexander V. Chernikov 2335f379342SAlexander V. Chernikov free(cfg, M_IPFW); 2345f379342SAlexander V. Chernikov } 2355f379342SAlexander V. Chernikov 2365f379342SAlexander V. Chernikov /* 2375f379342SAlexander V. Chernikov * Provide algo-specific table info 2385f379342SAlexander V. Chernikov */ 2395f379342SAlexander V. Chernikov static void 2405f379342SAlexander V. Chernikov ta_dump_radix_tinfo(void *ta_state, struct table_info *ti, ipfw_ta_tinfo *tinfo) 2415f379342SAlexander V. Chernikov { 2425f379342SAlexander V. Chernikov struct radix_cfg *cfg; 2435f379342SAlexander V. Chernikov 2445f379342SAlexander V. Chernikov cfg = (struct radix_cfg *)ta_state; 2455f379342SAlexander V. Chernikov 2465f379342SAlexander V. Chernikov tinfo->flags = IPFW_TATFLAGS_AFDATA | IPFW_TATFLAGS_AFITEM; 2475f379342SAlexander V. Chernikov tinfo->taclass4 = IPFW_TACLASS_RADIX; 2485f379342SAlexander V. Chernikov tinfo->count4 = cfg->count4; 2495f379342SAlexander V. Chernikov tinfo->itemsize4 = sizeof(struct radix_cidr_entry); 2505f379342SAlexander V. Chernikov tinfo->taclass6 = IPFW_TACLASS_RADIX; 2515f379342SAlexander V. Chernikov tinfo->count6 = cfg->count6; 2525f379342SAlexander V. Chernikov tinfo->itemsize6 = sizeof(struct radix_cidr_xentry); 2539f7d47b0SAlexander V. Chernikov } 2549f7d47b0SAlexander V. Chernikov 2559f7d47b0SAlexander V. Chernikov static int 25681d3153dSAlexander V. Chernikov ta_dump_radix_tentry(void *ta_state, struct table_info *ti, void *e, 25781d3153dSAlexander V. Chernikov ipfw_obj_tentry *tent) 2589f7d47b0SAlexander V. Chernikov { 259e0a8b9eeSAlexander V. Chernikov struct radix_cidr_entry *n; 260e0a8b9eeSAlexander V. Chernikov struct radix_cidr_xentry *xn; 2619f7d47b0SAlexander V. Chernikov 262e0a8b9eeSAlexander V. Chernikov n = (struct radix_cidr_entry *)e; 2639f7d47b0SAlexander V. Chernikov 2649f7d47b0SAlexander V. Chernikov /* Guess IPv4/IPv6 radix by sockaddr family */ 2659f7d47b0SAlexander V. Chernikov if (n->addr.sin_family == AF_INET) { 26681d3153dSAlexander V. Chernikov tent->k.addr.s_addr = n->addr.sin_addr.s_addr; 267e0a8b9eeSAlexander V. Chernikov tent->masklen = n->masklen; 26881d3153dSAlexander V. Chernikov tent->subtype = AF_INET; 26981d3153dSAlexander V. Chernikov tent->value = n->value; 2709f7d47b0SAlexander V. Chernikov #ifdef INET6 2719f7d47b0SAlexander V. Chernikov } else { 272e0a8b9eeSAlexander V. Chernikov xn = (struct radix_cidr_xentry *)e; 273e0a8b9eeSAlexander V. Chernikov memcpy(&tent->k, &xn->addr6.sin6_addr, sizeof(struct in6_addr)); 274e0a8b9eeSAlexander V. Chernikov tent->masklen = xn->masklen; 27581d3153dSAlexander V. Chernikov tent->subtype = AF_INET6; 27681d3153dSAlexander V. Chernikov tent->value = xn->value; 2779f7d47b0SAlexander V. Chernikov #endif 2789f7d47b0SAlexander V. Chernikov } 2799f7d47b0SAlexander V. Chernikov 2809f7d47b0SAlexander V. Chernikov return (0); 2819f7d47b0SAlexander V. Chernikov } 2829f7d47b0SAlexander V. Chernikov 28381d3153dSAlexander V. Chernikov static int 284914bffb6SAlexander V. Chernikov ta_find_radix_tentry(void *ta_state, struct table_info *ti, 285914bffb6SAlexander V. Chernikov ipfw_obj_tentry *tent) 28681d3153dSAlexander V. Chernikov { 28781d3153dSAlexander V. Chernikov struct radix_node_head *rnh; 28881d3153dSAlexander V. Chernikov void *e; 28981d3153dSAlexander V. Chernikov 29081d3153dSAlexander V. Chernikov e = NULL; 291914bffb6SAlexander V. Chernikov if (tent->subtype == AF_INET) { 29281d3153dSAlexander V. Chernikov struct sockaddr_in sa; 29381d3153dSAlexander V. Chernikov KEY_LEN(sa) = KEY_LEN_INET; 294914bffb6SAlexander V. Chernikov sa.sin_addr.s_addr = tent->k.addr.s_addr; 29581d3153dSAlexander V. Chernikov rnh = (struct radix_node_head *)ti->state; 29681d3153dSAlexander V. Chernikov e = rnh->rnh_matchaddr(&sa, rnh); 29781d3153dSAlexander V. Chernikov } else { 298e0a8b9eeSAlexander V. Chernikov struct sa_in6 sa6; 29981d3153dSAlexander V. Chernikov KEY_LEN(sa6) = KEY_LEN_INET6; 300914bffb6SAlexander V. Chernikov memcpy(&sa6.sin6_addr, &tent->k.addr6, sizeof(struct in6_addr)); 30181d3153dSAlexander V. Chernikov rnh = (struct radix_node_head *)ti->xstate; 30281d3153dSAlexander V. Chernikov e = rnh->rnh_matchaddr(&sa6, rnh); 30381d3153dSAlexander V. Chernikov } 30481d3153dSAlexander V. Chernikov 30581d3153dSAlexander V. Chernikov if (e != NULL) { 30681d3153dSAlexander V. Chernikov ta_dump_radix_tentry(ta_state, ti, e, tent); 30781d3153dSAlexander V. Chernikov return (0); 30881d3153dSAlexander V. Chernikov } 30981d3153dSAlexander V. Chernikov 31081d3153dSAlexander V. Chernikov return (ENOENT); 31181d3153dSAlexander V. Chernikov } 31281d3153dSAlexander V. Chernikov 3139f7d47b0SAlexander V. Chernikov static void 3149f7d47b0SAlexander V. Chernikov ta_foreach_radix(void *ta_state, struct table_info *ti, ta_foreach_f *f, 3159f7d47b0SAlexander V. Chernikov void *arg) 3169f7d47b0SAlexander V. Chernikov { 3179f7d47b0SAlexander V. Chernikov struct radix_node_head *rnh; 3189f7d47b0SAlexander V. Chernikov 3199f7d47b0SAlexander V. Chernikov rnh = (struct radix_node_head *)(ti->state); 3209f7d47b0SAlexander V. Chernikov rnh->rnh_walktree(rnh, (walktree_f_t *)f, arg); 3219f7d47b0SAlexander V. Chernikov 3229f7d47b0SAlexander V. Chernikov rnh = (struct radix_node_head *)(ti->xstate); 3239f7d47b0SAlexander V. Chernikov rnh->rnh_walktree(rnh, (walktree_f_t *)f, arg); 3249f7d47b0SAlexander V. Chernikov } 3259f7d47b0SAlexander V. Chernikov 3269f7d47b0SAlexander V. Chernikov 3279f7d47b0SAlexander V. Chernikov #ifdef INET6 3289f7d47b0SAlexander V. Chernikov static inline void 3299f7d47b0SAlexander V. Chernikov ipv6_writemask(struct in6_addr *addr6, uint8_t mask) 3309f7d47b0SAlexander V. Chernikov { 3319f7d47b0SAlexander V. Chernikov uint32_t *cp; 3329f7d47b0SAlexander V. Chernikov 3339f7d47b0SAlexander V. Chernikov for (cp = (uint32_t *)addr6; mask >= 32; mask -= 32) 3349f7d47b0SAlexander V. Chernikov *cp++ = 0xFFFFFFFF; 3359f7d47b0SAlexander V. Chernikov *cp = htonl(mask ? ~((1 << (32 - mask)) - 1) : 0); 3369f7d47b0SAlexander V. Chernikov } 3379f7d47b0SAlexander V. Chernikov #endif 3389f7d47b0SAlexander V. Chernikov 3392e324d29SAlexander V. Chernikov static void 3402e324d29SAlexander V. Chernikov tei_to_sockaddr_ent(struct tentry_info *tei, struct sockaddr *sa, 3412e324d29SAlexander V. Chernikov struct sockaddr *ma, int *set_mask) 3422e324d29SAlexander V. Chernikov { 3432e324d29SAlexander V. Chernikov int mlen; 3442e324d29SAlexander V. Chernikov struct sockaddr_in *addr, *mask; 345*720ee730SAlexander V. Chernikov struct sa_in6 *addr6, *mask6; 3462e324d29SAlexander V. Chernikov in_addr_t a4; 3472e324d29SAlexander V. Chernikov 3482e324d29SAlexander V. Chernikov mlen = tei->masklen; 3492e324d29SAlexander V. Chernikov 3502e324d29SAlexander V. Chernikov if (tei->subtype == AF_INET) { 3512e324d29SAlexander V. Chernikov #ifdef INET 3522e324d29SAlexander V. Chernikov addr = (struct sockaddr_in *)sa; 3532e324d29SAlexander V. Chernikov mask = (struct sockaddr_in *)ma; 3542e324d29SAlexander V. Chernikov /* Set 'total' structure length */ 3552e324d29SAlexander V. Chernikov KEY_LEN(*addr) = KEY_LEN_INET; 3562e324d29SAlexander V. Chernikov KEY_LEN(*mask) = KEY_LEN_INET; 3572e324d29SAlexander V. Chernikov addr->sin_family = AF_INET; 3582e324d29SAlexander V. Chernikov mask->sin_addr.s_addr = 3592e324d29SAlexander V. Chernikov htonl(mlen ? ~((1 << (32 - mlen)) - 1) : 0); 3602e324d29SAlexander V. Chernikov a4 = *((in_addr_t *)tei->paddr); 3612e324d29SAlexander V. Chernikov addr->sin_addr.s_addr = a4 & mask->sin_addr.s_addr; 3622e324d29SAlexander V. Chernikov if (mlen != 32) 3632e324d29SAlexander V. Chernikov *set_mask = 1; 3642e324d29SAlexander V. Chernikov else 3652e324d29SAlexander V. Chernikov *set_mask = 0; 3662e324d29SAlexander V. Chernikov #endif 3672e324d29SAlexander V. Chernikov #ifdef INET6 3682e324d29SAlexander V. Chernikov } else if (tei->subtype == AF_INET6) { 3692e324d29SAlexander V. Chernikov /* IPv6 case */ 370*720ee730SAlexander V. Chernikov addr6 = (struct sa_in6 *)sa; 371*720ee730SAlexander V. Chernikov mask6 = (struct sa_in6 *)ma; 3722e324d29SAlexander V. Chernikov /* Set 'total' structure length */ 3732e324d29SAlexander V. Chernikov KEY_LEN(*addr6) = KEY_LEN_INET6; 3742e324d29SAlexander V. Chernikov KEY_LEN(*mask6) = KEY_LEN_INET6; 3752e324d29SAlexander V. Chernikov addr6->sin6_family = AF_INET6; 3762e324d29SAlexander V. Chernikov ipv6_writemask(&mask6->sin6_addr, mlen); 3772e324d29SAlexander V. Chernikov memcpy(&addr6->sin6_addr, tei->paddr, sizeof(struct in6_addr)); 3782e324d29SAlexander V. Chernikov APPLY_MASK(&addr6->sin6_addr, &mask6->sin6_addr); 3792e324d29SAlexander V. Chernikov if (mlen != 128) 3802e324d29SAlexander V. Chernikov *set_mask = 1; 3812e324d29SAlexander V. Chernikov else 3822e324d29SAlexander V. Chernikov *set_mask = 0; 3832e324d29SAlexander V. Chernikov } 3842e324d29SAlexander V. Chernikov #endif 3852e324d29SAlexander V. Chernikov } 3869f7d47b0SAlexander V. Chernikov 3879f7d47b0SAlexander V. Chernikov static int 388a399f8beSAlexander V. Chernikov ta_prepare_add_radix(struct ip_fw_chain *ch, struct tentry_info *tei, 38968394ec8SAlexander V. Chernikov void *ta_buf) 3909f7d47b0SAlexander V. Chernikov { 3919f7d47b0SAlexander V. Chernikov struct ta_buf_cidr *tb; 392e0a8b9eeSAlexander V. Chernikov struct radix_cidr_entry *ent; 393e0a8b9eeSAlexander V. Chernikov struct radix_cidr_xentry *xent; 3942e324d29SAlexander V. Chernikov struct sockaddr *addr, *mask; 3952e324d29SAlexander V. Chernikov int mlen, set_mask; 3969f7d47b0SAlexander V. Chernikov 3979f7d47b0SAlexander V. Chernikov tb = (struct ta_buf_cidr *)ta_buf; 3989f7d47b0SAlexander V. Chernikov 3999f7d47b0SAlexander V. Chernikov mlen = tei->masklen; 4002e324d29SAlexander V. Chernikov set_mask = 0; 4019f7d47b0SAlexander V. Chernikov 402ac35ff17SAlexander V. Chernikov if (tei->subtype == AF_INET) { 4039f7d47b0SAlexander V. Chernikov #ifdef INET 4049f7d47b0SAlexander V. Chernikov if (mlen > 32) 4059f7d47b0SAlexander V. Chernikov return (EINVAL); 4069f7d47b0SAlexander V. Chernikov ent = malloc(sizeof(*ent), M_IPFW_TBL, M_WAITOK | M_ZERO); 4079f7d47b0SAlexander V. Chernikov ent->value = tei->value; 408e0a8b9eeSAlexander V. Chernikov ent->masklen = mlen; 4092e324d29SAlexander V. Chernikov 4102e324d29SAlexander V. Chernikov addr = (struct sockaddr *)&ent->addr; 4112e324d29SAlexander V. Chernikov mask = (struct sockaddr *)&tb->addr.a4.ma; 4129f7d47b0SAlexander V. Chernikov tb->ent_ptr = ent; 4139f7d47b0SAlexander V. Chernikov #endif 4149f7d47b0SAlexander V. Chernikov #ifdef INET6 415ac35ff17SAlexander V. Chernikov } else if (tei->subtype == AF_INET6) { 4169f7d47b0SAlexander V. Chernikov /* IPv6 case */ 4179f7d47b0SAlexander V. Chernikov if (mlen > 128) 4189f7d47b0SAlexander V. Chernikov return (EINVAL); 4199f7d47b0SAlexander V. Chernikov xent = malloc(sizeof(*xent), M_IPFW_TBL, M_WAITOK | M_ZERO); 4209f7d47b0SAlexander V. Chernikov xent->value = tei->value; 421e0a8b9eeSAlexander V. Chernikov xent->masklen = mlen; 4222e324d29SAlexander V. Chernikov 4232e324d29SAlexander V. Chernikov addr = (struct sockaddr *)&xent->addr6; 4242e324d29SAlexander V. Chernikov mask = (struct sockaddr *)&tb->addr.a6.ma; 4259f7d47b0SAlexander V. Chernikov tb->ent_ptr = xent; 4269f7d47b0SAlexander V. Chernikov #endif 4279f7d47b0SAlexander V. Chernikov } else { 4289f7d47b0SAlexander V. Chernikov /* Unknown CIDR type */ 4299f7d47b0SAlexander V. Chernikov return (EINVAL); 4309f7d47b0SAlexander V. Chernikov } 4319f7d47b0SAlexander V. Chernikov 4322e324d29SAlexander V. Chernikov tei_to_sockaddr_ent(tei, addr, mask, &set_mask); 4332e324d29SAlexander V. Chernikov /* Set pointers */ 4342e324d29SAlexander V. Chernikov tb->addr_ptr = addr; 4352e324d29SAlexander V. Chernikov if (set_mask != 0) 4362e324d29SAlexander V. Chernikov tb->mask_ptr = mask; 4372e324d29SAlexander V. Chernikov 4389f7d47b0SAlexander V. Chernikov return (0); 4399f7d47b0SAlexander V. Chernikov } 4409f7d47b0SAlexander V. Chernikov 4419f7d47b0SAlexander V. Chernikov static int 442a399f8beSAlexander V. Chernikov ta_add_radix(void *ta_state, struct table_info *ti, struct tentry_info *tei, 443b6ee846eSAlexander V. Chernikov void *ta_buf, uint32_t *pnum) 4449f7d47b0SAlexander V. Chernikov { 4455f379342SAlexander V. Chernikov struct radix_cfg *cfg; 4469f7d47b0SAlexander V. Chernikov struct radix_node_head *rnh; 4479f7d47b0SAlexander V. Chernikov struct radix_node *rn; 4489f7d47b0SAlexander V. Chernikov struct ta_buf_cidr *tb; 449648e8380SAlexander V. Chernikov uint32_t *old_value, value; 4509f7d47b0SAlexander V. Chernikov 4515f379342SAlexander V. Chernikov cfg = (struct radix_cfg *)ta_state; 4529f7d47b0SAlexander V. Chernikov tb = (struct ta_buf_cidr *)ta_buf; 4539f7d47b0SAlexander V. Chernikov 454ac35ff17SAlexander V. Chernikov if (tei->subtype == AF_INET) 4559f7d47b0SAlexander V. Chernikov rnh = ti->state; 4569f7d47b0SAlexander V. Chernikov else 4579f7d47b0SAlexander V. Chernikov rnh = ti->xstate; 4589f7d47b0SAlexander V. Chernikov 4594c0c07a5SAlexander V. Chernikov /* Search for an entry first */ 4604c0c07a5SAlexander V. Chernikov rn = rnh->rnh_lookup(tb->addr_ptr, tb->mask_ptr, rnh); 4614c0c07a5SAlexander V. Chernikov if (rn != NULL) { 462ac35ff17SAlexander V. Chernikov if ((tei->flags & TEI_FLAGS_UPDATE) == 0) 4639f7d47b0SAlexander V. Chernikov return (EEXIST); 464ac35ff17SAlexander V. Chernikov /* Record already exists. Update value if we're asked to */ 465648e8380SAlexander V. Chernikov if (tei->subtype == AF_INET) 466648e8380SAlexander V. Chernikov old_value = &((struct radix_cidr_entry *)rn)->value; 467648e8380SAlexander V. Chernikov else 468648e8380SAlexander V. Chernikov old_value = &((struct radix_cidr_xentry *)rn)->value; 469648e8380SAlexander V. Chernikov 470648e8380SAlexander V. Chernikov value = *old_value; 471648e8380SAlexander V. Chernikov *old_value = tei->value; 472648e8380SAlexander V. Chernikov tei->value = value; 473ac35ff17SAlexander V. Chernikov 474ac35ff17SAlexander V. Chernikov /* Indicate that update has happened instead of addition */ 475ac35ff17SAlexander V. Chernikov tei->flags |= TEI_FLAGS_UPDATED; 476adea6201SAlexander V. Chernikov *pnum = 0; 477e0a8b9eeSAlexander V. Chernikov 478e0a8b9eeSAlexander V. Chernikov return (0); 479ac35ff17SAlexander V. Chernikov } 480ac35ff17SAlexander V. Chernikov 4814c0c07a5SAlexander V. Chernikov if ((tei->flags & TEI_FLAGS_DONTADD) != 0) 4824c0c07a5SAlexander V. Chernikov return (EFBIG); 4834c0c07a5SAlexander V. Chernikov 4844c0c07a5SAlexander V. Chernikov rn = rnh->rnh_addaddr(tb->addr_ptr, tb->mask_ptr, rnh, tb->ent_ptr); 4854c0c07a5SAlexander V. Chernikov if (rn == NULL) { 4864c0c07a5SAlexander V. Chernikov /* Unknown error */ 4874c0c07a5SAlexander V. Chernikov return (EINVAL); 4884c0c07a5SAlexander V. Chernikov } 4894c0c07a5SAlexander V. Chernikov 4905f379342SAlexander V. Chernikov if (tei->subtype == AF_INET) 4915f379342SAlexander V. Chernikov cfg->count4++; 4925f379342SAlexander V. Chernikov else 4935f379342SAlexander V. Chernikov cfg->count6++; 494ac35ff17SAlexander V. Chernikov tb->ent_ptr = NULL; 495adea6201SAlexander V. Chernikov *pnum = 1; 4969f7d47b0SAlexander V. Chernikov 4979f7d47b0SAlexander V. Chernikov return (0); 4989f7d47b0SAlexander V. Chernikov } 4999f7d47b0SAlexander V. Chernikov 5009f7d47b0SAlexander V. Chernikov static int 501a399f8beSAlexander V. Chernikov ta_prepare_del_radix(struct ip_fw_chain *ch, struct tentry_info *tei, 50268394ec8SAlexander V. Chernikov void *ta_buf) 5039f7d47b0SAlexander V. Chernikov { 5049f7d47b0SAlexander V. Chernikov struct ta_buf_cidr *tb; 5052e324d29SAlexander V. Chernikov struct sockaddr *addr, *mask; 5062e324d29SAlexander V. Chernikov int mlen, set_mask; 5079f7d47b0SAlexander V. Chernikov 5089f7d47b0SAlexander V. Chernikov tb = (struct ta_buf_cidr *)ta_buf; 5099f7d47b0SAlexander V. Chernikov 5109f7d47b0SAlexander V. Chernikov mlen = tei->masklen; 5112e324d29SAlexander V. Chernikov set_mask = 0; 5129f7d47b0SAlexander V. Chernikov 513ac35ff17SAlexander V. Chernikov if (tei->subtype == AF_INET) { 514e0a8b9eeSAlexander V. Chernikov if (mlen > 32) 515e0a8b9eeSAlexander V. Chernikov return (EINVAL); 5162e324d29SAlexander V. Chernikov 5172e324d29SAlexander V. Chernikov addr = (struct sockaddr *)&tb->addr.a4.sa; 5182e324d29SAlexander V. Chernikov mask = (struct sockaddr *)&tb->addr.a4.ma; 5199f7d47b0SAlexander V. Chernikov #ifdef INET6 520ac35ff17SAlexander V. Chernikov } else if (tei->subtype == AF_INET6) { 5219f7d47b0SAlexander V. Chernikov if (mlen > 128) 5229f7d47b0SAlexander V. Chernikov return (EINVAL); 5232e324d29SAlexander V. Chernikov 5242e324d29SAlexander V. Chernikov addr = (struct sockaddr *)&tb->addr.a6.sa; 5252e324d29SAlexander V. Chernikov mask = (struct sockaddr *)&tb->addr.a6.ma; 5269f7d47b0SAlexander V. Chernikov #endif 5279f7d47b0SAlexander V. Chernikov } else 5289f7d47b0SAlexander V. Chernikov return (EINVAL); 5299f7d47b0SAlexander V. Chernikov 5302e324d29SAlexander V. Chernikov tei_to_sockaddr_ent(tei, addr, mask, &set_mask); 5312e324d29SAlexander V. Chernikov tb->addr_ptr = addr; 5322e324d29SAlexander V. Chernikov if (set_mask != 0) 5332e324d29SAlexander V. Chernikov tb->mask_ptr = mask; 5342e324d29SAlexander V. Chernikov 5359f7d47b0SAlexander V. Chernikov return (0); 5369f7d47b0SAlexander V. Chernikov } 5379f7d47b0SAlexander V. Chernikov 5389f7d47b0SAlexander V. Chernikov static int 539a399f8beSAlexander V. Chernikov ta_del_radix(void *ta_state, struct table_info *ti, struct tentry_info *tei, 540b6ee846eSAlexander V. Chernikov void *ta_buf, uint32_t *pnum) 5419f7d47b0SAlexander V. Chernikov { 5425f379342SAlexander V. Chernikov struct radix_cfg *cfg; 5439f7d47b0SAlexander V. Chernikov struct radix_node_head *rnh; 5449f7d47b0SAlexander V. Chernikov struct radix_node *rn; 5459f7d47b0SAlexander V. Chernikov struct ta_buf_cidr *tb; 5469f7d47b0SAlexander V. Chernikov 5475f379342SAlexander V. Chernikov cfg = (struct radix_cfg *)ta_state; 5489f7d47b0SAlexander V. Chernikov tb = (struct ta_buf_cidr *)ta_buf; 5499f7d47b0SAlexander V. Chernikov 550ac35ff17SAlexander V. Chernikov if (tei->subtype == AF_INET) 5519f7d47b0SAlexander V. Chernikov rnh = ti->state; 5529f7d47b0SAlexander V. Chernikov else 5539f7d47b0SAlexander V. Chernikov rnh = ti->xstate; 5549f7d47b0SAlexander V. Chernikov 5559f7d47b0SAlexander V. Chernikov rn = rnh->rnh_deladdr(tb->addr_ptr, tb->mask_ptr, rnh); 5569f7d47b0SAlexander V. Chernikov 557648e8380SAlexander V. Chernikov /* Save entry value to @tei */ 558648e8380SAlexander V. Chernikov if (tei->subtype == AF_INET) 559648e8380SAlexander V. Chernikov tei->value = ((struct radix_cidr_entry *)rn)->value; 560648e8380SAlexander V. Chernikov else 561648e8380SAlexander V. Chernikov tei->value = ((struct radix_cidr_xentry *)rn)->value; 562648e8380SAlexander V. Chernikov 5639f7d47b0SAlexander V. Chernikov tb->ent_ptr = rn; 5649f7d47b0SAlexander V. Chernikov 5659f7d47b0SAlexander V. Chernikov if (rn == NULL) 56681d3153dSAlexander V. Chernikov return (ENOENT); 5679f7d47b0SAlexander V. Chernikov 5685f379342SAlexander V. Chernikov if (tei->subtype == AF_INET) 5695f379342SAlexander V. Chernikov cfg->count4--; 5705f379342SAlexander V. Chernikov else 5715f379342SAlexander V. Chernikov cfg->count6--; 572adea6201SAlexander V. Chernikov *pnum = 1; 573adea6201SAlexander V. Chernikov 5749f7d47b0SAlexander V. Chernikov return (0); 5759f7d47b0SAlexander V. Chernikov } 5769f7d47b0SAlexander V. Chernikov 5779f7d47b0SAlexander V. Chernikov static void 578a399f8beSAlexander V. Chernikov ta_flush_radix_entry(struct ip_fw_chain *ch, struct tentry_info *tei, 57968394ec8SAlexander V. Chernikov void *ta_buf) 5809f7d47b0SAlexander V. Chernikov { 5819f7d47b0SAlexander V. Chernikov struct ta_buf_cidr *tb; 5829f7d47b0SAlexander V. Chernikov 5839f7d47b0SAlexander V. Chernikov tb = (struct ta_buf_cidr *)ta_buf; 5849f7d47b0SAlexander V. Chernikov 585ac35ff17SAlexander V. Chernikov if (tb->ent_ptr != NULL) 5869f7d47b0SAlexander V. Chernikov free(tb->ent_ptr, M_IPFW_TBL); 5879f7d47b0SAlexander V. Chernikov } 5889f7d47b0SAlexander V. Chernikov 589b6ee846eSAlexander V. Chernikov static int 590b6ee846eSAlexander V. Chernikov ta_has_space_radix(void *ta_state, struct table_info *ti, uint32_t count, 591b6ee846eSAlexander V. Chernikov uint64_t *pflags) 592b6ee846eSAlexander V. Chernikov { 593b6ee846eSAlexander V. Chernikov 594b6ee846eSAlexander V. Chernikov /* 5950bce0c23SAlexander V. Chernikov * radix does not require additional memory allocations 596b6ee846eSAlexander V. Chernikov * other than nodes itself. Adding new masks to the tree do 597b6ee846eSAlexander V. Chernikov * but we don't have any API to call (and we don't known which 598b6ee846eSAlexander V. Chernikov * sizes do we need). 599b6ee846eSAlexander V. Chernikov */ 600b6ee846eSAlexander V. Chernikov return (1); 601b6ee846eSAlexander V. Chernikov } 602b6ee846eSAlexander V. Chernikov 60374b941f0SAlexander V. Chernikov struct table_algo cidr_radix = { 604adea6201SAlexander V. Chernikov .name = "cidr:radix", 6059d099b4fSAlexander V. Chernikov .type = IPFW_TABLE_CIDR, 60657a1cf95SAlexander V. Chernikov .flags = TA_FLAG_DEFAULT, 60757a1cf95SAlexander V. Chernikov .ta_buf_size = sizeof(struct ta_buf_cidr), 6089f7d47b0SAlexander V. Chernikov .init = ta_init_radix, 6099f7d47b0SAlexander V. Chernikov .destroy = ta_destroy_radix, 610a399f8beSAlexander V. Chernikov .prepare_add = ta_prepare_add_radix, 611a399f8beSAlexander V. Chernikov .prepare_del = ta_prepare_del_radix, 612a399f8beSAlexander V. Chernikov .add = ta_add_radix, 613a399f8beSAlexander V. Chernikov .del = ta_del_radix, 614a399f8beSAlexander V. Chernikov .flush_entry = ta_flush_radix_entry, 6159f7d47b0SAlexander V. Chernikov .foreach = ta_foreach_radix, 61681d3153dSAlexander V. Chernikov .dump_tentry = ta_dump_radix_tentry, 61781d3153dSAlexander V. Chernikov .find_tentry = ta_find_radix_tentry, 6185f379342SAlexander V. Chernikov .dump_tinfo = ta_dump_radix_tinfo, 619b6ee846eSAlexander V. Chernikov .has_space = ta_has_space_radix, 6209f7d47b0SAlexander V. Chernikov }; 6219f7d47b0SAlexander V. Chernikov 6229f7d47b0SAlexander V. Chernikov 6239f7d47b0SAlexander V. Chernikov /* 62474b941f0SAlexander V. Chernikov * cidr:hash cmds 62574b941f0SAlexander V. Chernikov * 62674b941f0SAlexander V. Chernikov * 62774b941f0SAlexander V. Chernikov * ti->data: 62874b941f0SAlexander V. Chernikov * [inv.mask4][inv.mask6][log2hsize4][log2hsize6] 62974b941f0SAlexander V. Chernikov * [ 8][ 8[ 8][ 8] 63074b941f0SAlexander V. Chernikov * 63174b941f0SAlexander V. Chernikov * inv.mask4: 32 - mask 63274b941f0SAlexander V. Chernikov * inv.mask6: 63374b941f0SAlexander V. Chernikov * 1) _slow lookup: mask 63474b941f0SAlexander V. Chernikov * 2) _aligned: (128 - mask) / 8 63574b941f0SAlexander V. Chernikov * 3) _64: 8 636ce2817b5SAlexander V. Chernikov * 637ce2817b5SAlexander V. Chernikov * 638ce2817b5SAlexander V. Chernikov * pflags: 639ce2817b5SAlexander V. Chernikov * [v4=1/v6=0][hsize] 640ce2817b5SAlexander V. Chernikov * [ 32][ 32] 64174b941f0SAlexander V. Chernikov */ 64274b941f0SAlexander V. Chernikov 64374b941f0SAlexander V. Chernikov struct chashentry; 64474b941f0SAlexander V. Chernikov 64574b941f0SAlexander V. Chernikov SLIST_HEAD(chashbhead, chashentry); 64674b941f0SAlexander V. Chernikov 64774b941f0SAlexander V. Chernikov struct chash_cfg { 64874b941f0SAlexander V. Chernikov struct chashbhead *head4; 64974b941f0SAlexander V. Chernikov struct chashbhead *head6; 65074b941f0SAlexander V. Chernikov size_t size4; 65174b941f0SAlexander V. Chernikov size_t size6; 652ce2817b5SAlexander V. Chernikov size_t items4; 653ce2817b5SAlexander V. Chernikov size_t items6; 65474b941f0SAlexander V. Chernikov uint8_t mask4; 65574b941f0SAlexander V. Chernikov uint8_t mask6; 65674b941f0SAlexander V. Chernikov }; 65774b941f0SAlexander V. Chernikov 65874b941f0SAlexander V. Chernikov struct chashentry { 65974b941f0SAlexander V. Chernikov SLIST_ENTRY(chashentry) next; 66074b941f0SAlexander V. Chernikov uint32_t value; 66174b941f0SAlexander V. Chernikov uint32_t type; 66274b941f0SAlexander V. Chernikov union { 66374b941f0SAlexander V. Chernikov uint32_t a4; /* Host format */ 66474b941f0SAlexander V. Chernikov struct in6_addr a6; /* Network format */ 66574b941f0SAlexander V. Chernikov } a; 66674b941f0SAlexander V. Chernikov }; 66774b941f0SAlexander V. Chernikov 6680bce0c23SAlexander V. Chernikov struct ta_buf_chash 6690bce0c23SAlexander V. Chernikov { 6700bce0c23SAlexander V. Chernikov void *ent_ptr; 6710bce0c23SAlexander V. Chernikov struct chashentry ent; 6720bce0c23SAlexander V. Chernikov }; 6730bce0c23SAlexander V. Chernikov 6740bce0c23SAlexander V. Chernikov 67574b941f0SAlexander V. Chernikov static __inline uint32_t 67674b941f0SAlexander V. Chernikov hash_ip(uint32_t addr, int hsize) 67774b941f0SAlexander V. Chernikov { 67874b941f0SAlexander V. Chernikov 67974b941f0SAlexander V. Chernikov return (addr % (hsize - 1)); 68074b941f0SAlexander V. Chernikov } 68174b941f0SAlexander V. Chernikov 68274b941f0SAlexander V. Chernikov static __inline uint32_t 68374b941f0SAlexander V. Chernikov hash_ip6(struct in6_addr *addr6, int hsize) 68474b941f0SAlexander V. Chernikov { 68574b941f0SAlexander V. Chernikov uint32_t i; 68674b941f0SAlexander V. Chernikov 68774b941f0SAlexander V. Chernikov i = addr6->s6_addr32[0] ^ addr6->s6_addr32[1] ^ 68874b941f0SAlexander V. Chernikov addr6->s6_addr32[2] ^ addr6->s6_addr32[3]; 68974b941f0SAlexander V. Chernikov 69074b941f0SAlexander V. Chernikov return (i % (hsize - 1)); 69174b941f0SAlexander V. Chernikov } 69274b941f0SAlexander V. Chernikov 69374b941f0SAlexander V. Chernikov 69474b941f0SAlexander V. Chernikov static __inline uint16_t 69574b941f0SAlexander V. Chernikov hash_ip64(struct in6_addr *addr6, int hsize) 69674b941f0SAlexander V. Chernikov { 69774b941f0SAlexander V. Chernikov uint32_t i; 69874b941f0SAlexander V. Chernikov 69974b941f0SAlexander V. Chernikov i = addr6->s6_addr32[0] ^ addr6->s6_addr32[1]; 70074b941f0SAlexander V. Chernikov 70174b941f0SAlexander V. Chernikov return (i % (hsize - 1)); 70274b941f0SAlexander V. Chernikov } 70374b941f0SAlexander V. Chernikov 70474b941f0SAlexander V. Chernikov 70574b941f0SAlexander V. Chernikov static __inline uint32_t 70674b941f0SAlexander V. Chernikov hash_ip6_slow(struct in6_addr *addr6, void *key, int mask, int hsize) 70774b941f0SAlexander V. Chernikov { 70874b941f0SAlexander V. Chernikov struct in6_addr mask6; 70974b941f0SAlexander V. Chernikov 71074b941f0SAlexander V. Chernikov ipv6_writemask(&mask6, mask); 71174b941f0SAlexander V. Chernikov memcpy(addr6, key, sizeof(struct in6_addr)); 71274b941f0SAlexander V. Chernikov APPLY_MASK(addr6, &mask6); 71374b941f0SAlexander V. Chernikov return (hash_ip6(addr6, hsize)); 71474b941f0SAlexander V. Chernikov } 71574b941f0SAlexander V. Chernikov 71674b941f0SAlexander V. Chernikov static __inline uint32_t 71774b941f0SAlexander V. Chernikov hash_ip6_al(struct in6_addr *addr6, void *key, int mask, int hsize) 71874b941f0SAlexander V. Chernikov { 71974b941f0SAlexander V. Chernikov uint64_t *paddr; 72074b941f0SAlexander V. Chernikov 72174b941f0SAlexander V. Chernikov paddr = (uint64_t *)addr6; 72274b941f0SAlexander V. Chernikov *paddr = 0; 72374b941f0SAlexander V. Chernikov *(paddr + 1) = 0; 72474b941f0SAlexander V. Chernikov memcpy(addr6, key, mask); 72574b941f0SAlexander V. Chernikov return (hash_ip6(addr6, hsize)); 72674b941f0SAlexander V. Chernikov } 72774b941f0SAlexander V. Chernikov 72874b941f0SAlexander V. Chernikov static int 72974b941f0SAlexander V. Chernikov ta_lookup_chash_slow(struct table_info *ti, void *key, uint32_t keylen, 73074b941f0SAlexander V. Chernikov uint32_t *val) 73174b941f0SAlexander V. Chernikov { 73274b941f0SAlexander V. Chernikov struct chashbhead *head; 73374b941f0SAlexander V. Chernikov struct chashentry *ent; 73474b941f0SAlexander V. Chernikov uint16_t hash, hsize; 73574b941f0SAlexander V. Chernikov uint8_t imask; 73674b941f0SAlexander V. Chernikov 73774b941f0SAlexander V. Chernikov if (keylen == sizeof(in_addr_t)) { 73874b941f0SAlexander V. Chernikov head = (struct chashbhead *)ti->state; 73974b941f0SAlexander V. Chernikov imask = ti->data >> 24; 74074b941f0SAlexander V. Chernikov hsize = 1 << ((ti->data & 0xFFFF) >> 8); 74174b941f0SAlexander V. Chernikov uint32_t a; 74274b941f0SAlexander V. Chernikov a = ntohl(*((in_addr_t *)key)); 74374b941f0SAlexander V. Chernikov a = a >> imask; 74474b941f0SAlexander V. Chernikov hash = hash_ip(a, hsize); 74574b941f0SAlexander V. Chernikov SLIST_FOREACH(ent, &head[hash], next) { 74674b941f0SAlexander V. Chernikov if (ent->a.a4 == a) { 74774b941f0SAlexander V. Chernikov *val = ent->value; 74874b941f0SAlexander V. Chernikov return (1); 74974b941f0SAlexander V. Chernikov } 75074b941f0SAlexander V. Chernikov } 75174b941f0SAlexander V. Chernikov } else { 75274b941f0SAlexander V. Chernikov /* IPv6: worst scenario: non-round mask */ 75374b941f0SAlexander V. Chernikov struct in6_addr addr6; 75474b941f0SAlexander V. Chernikov head = (struct chashbhead *)ti->xstate; 75574b941f0SAlexander V. Chernikov imask = (ti->data & 0xFF0000) >> 16; 75674b941f0SAlexander V. Chernikov hsize = 1 << (ti->data & 0xFF); 75774b941f0SAlexander V. Chernikov hash = hash_ip6_slow(&addr6, key, imask, hsize); 75874b941f0SAlexander V. Chernikov SLIST_FOREACH(ent, &head[hash], next) { 75974b941f0SAlexander V. Chernikov if (memcmp(&ent->a.a6, &addr6, 16) == 0) { 76074b941f0SAlexander V. Chernikov *val = ent->value; 76174b941f0SAlexander V. Chernikov return (1); 76274b941f0SAlexander V. Chernikov } 76374b941f0SAlexander V. Chernikov } 76474b941f0SAlexander V. Chernikov } 76574b941f0SAlexander V. Chernikov 76674b941f0SAlexander V. Chernikov return (0); 76774b941f0SAlexander V. Chernikov } 76874b941f0SAlexander V. Chernikov 76974b941f0SAlexander V. Chernikov static int 77074b941f0SAlexander V. Chernikov ta_lookup_chash_aligned(struct table_info *ti, void *key, uint32_t keylen, 77174b941f0SAlexander V. Chernikov uint32_t *val) 77274b941f0SAlexander V. Chernikov { 77374b941f0SAlexander V. Chernikov struct chashbhead *head; 77474b941f0SAlexander V. Chernikov struct chashentry *ent; 77574b941f0SAlexander V. Chernikov uint16_t hash, hsize; 77674b941f0SAlexander V. Chernikov uint8_t imask; 77774b941f0SAlexander V. Chernikov 77874b941f0SAlexander V. Chernikov if (keylen == sizeof(in_addr_t)) { 77974b941f0SAlexander V. Chernikov head = (struct chashbhead *)ti->state; 78074b941f0SAlexander V. Chernikov imask = ti->data >> 24; 78174b941f0SAlexander V. Chernikov hsize = 1 << ((ti->data & 0xFFFF) >> 8); 78274b941f0SAlexander V. Chernikov uint32_t a; 78374b941f0SAlexander V. Chernikov a = ntohl(*((in_addr_t *)key)); 78474b941f0SAlexander V. Chernikov a = a >> imask; 78574b941f0SAlexander V. Chernikov hash = hash_ip(a, hsize); 78674b941f0SAlexander V. Chernikov SLIST_FOREACH(ent, &head[hash], next) { 78774b941f0SAlexander V. Chernikov if (ent->a.a4 == a) { 78874b941f0SAlexander V. Chernikov *val = ent->value; 78974b941f0SAlexander V. Chernikov return (1); 79074b941f0SAlexander V. Chernikov } 79174b941f0SAlexander V. Chernikov } 79274b941f0SAlexander V. Chernikov } else { 79374b941f0SAlexander V. Chernikov /* IPv6: aligned to 8bit mask */ 79474b941f0SAlexander V. Chernikov struct in6_addr addr6; 79574b941f0SAlexander V. Chernikov uint64_t *paddr, *ptmp; 79674b941f0SAlexander V. Chernikov head = (struct chashbhead *)ti->xstate; 79774b941f0SAlexander V. Chernikov imask = (ti->data & 0xFF0000) >> 16; 79874b941f0SAlexander V. Chernikov hsize = 1 << (ti->data & 0xFF); 79974b941f0SAlexander V. Chernikov 80074b941f0SAlexander V. Chernikov hash = hash_ip6_al(&addr6, key, imask, hsize); 80174b941f0SAlexander V. Chernikov paddr = (uint64_t *)&addr6; 80274b941f0SAlexander V. Chernikov SLIST_FOREACH(ent, &head[hash], next) { 80374b941f0SAlexander V. Chernikov ptmp = (uint64_t *)&ent->a.a6; 80474b941f0SAlexander V. Chernikov if (paddr[0] == ptmp[0] && paddr[1] == ptmp[1]) { 80574b941f0SAlexander V. Chernikov *val = ent->value; 80674b941f0SAlexander V. Chernikov return (1); 80774b941f0SAlexander V. Chernikov } 80874b941f0SAlexander V. Chernikov } 80974b941f0SAlexander V. Chernikov } 81074b941f0SAlexander V. Chernikov 81174b941f0SAlexander V. Chernikov return (0); 81274b941f0SAlexander V. Chernikov } 81374b941f0SAlexander V. Chernikov 81474b941f0SAlexander V. Chernikov static int 81574b941f0SAlexander V. Chernikov ta_lookup_chash_64(struct table_info *ti, void *key, uint32_t keylen, 81674b941f0SAlexander V. Chernikov uint32_t *val) 81774b941f0SAlexander V. Chernikov { 81874b941f0SAlexander V. Chernikov struct chashbhead *head; 81974b941f0SAlexander V. Chernikov struct chashentry *ent; 82074b941f0SAlexander V. Chernikov uint16_t hash, hsize; 82174b941f0SAlexander V. Chernikov uint8_t imask; 82274b941f0SAlexander V. Chernikov 82374b941f0SAlexander V. Chernikov if (keylen == sizeof(in_addr_t)) { 82474b941f0SAlexander V. Chernikov head = (struct chashbhead *)ti->state; 82574b941f0SAlexander V. Chernikov imask = ti->data >> 24; 82674b941f0SAlexander V. Chernikov hsize = 1 << ((ti->data & 0xFFFF) >> 8); 82774b941f0SAlexander V. Chernikov uint32_t a; 82874b941f0SAlexander V. Chernikov a = ntohl(*((in_addr_t *)key)); 82974b941f0SAlexander V. Chernikov a = a >> imask; 83074b941f0SAlexander V. Chernikov hash = hash_ip(a, hsize); 83174b941f0SAlexander V. Chernikov SLIST_FOREACH(ent, &head[hash], next) { 83274b941f0SAlexander V. Chernikov if (ent->a.a4 == a) { 83374b941f0SAlexander V. Chernikov *val = ent->value; 83474b941f0SAlexander V. Chernikov return (1); 83574b941f0SAlexander V. Chernikov } 83674b941f0SAlexander V. Chernikov } 83774b941f0SAlexander V. Chernikov } else { 83874b941f0SAlexander V. Chernikov /* IPv6: /64 */ 83974b941f0SAlexander V. Chernikov uint64_t a6, *paddr; 84074b941f0SAlexander V. Chernikov head = (struct chashbhead *)ti->xstate; 84174b941f0SAlexander V. Chernikov paddr = (uint64_t *)key; 84274b941f0SAlexander V. Chernikov hsize = 1 << (ti->data & 0xFF); 84374b941f0SAlexander V. Chernikov a6 = *paddr; 84474b941f0SAlexander V. Chernikov hash = hash_ip64((struct in6_addr *)key, hsize); 84574b941f0SAlexander V. Chernikov SLIST_FOREACH(ent, &head[hash], next) { 84674b941f0SAlexander V. Chernikov paddr = (uint64_t *)&ent->a.a6; 84774b941f0SAlexander V. Chernikov if (a6 == *paddr) { 84874b941f0SAlexander V. Chernikov *val = ent->value; 84974b941f0SAlexander V. Chernikov return (1); 85074b941f0SAlexander V. Chernikov } 85174b941f0SAlexander V. Chernikov } 85274b941f0SAlexander V. Chernikov } 85374b941f0SAlexander V. Chernikov 85474b941f0SAlexander V. Chernikov return (0); 85574b941f0SAlexander V. Chernikov } 85674b941f0SAlexander V. Chernikov 85774b941f0SAlexander V. Chernikov static int 8580bce0c23SAlexander V. Chernikov chash_parse_opts(struct chash_cfg *cfg, char *data) 85974b941f0SAlexander V. Chernikov { 86074b941f0SAlexander V. Chernikov char *pdel, *pend, *s; 86174b941f0SAlexander V. Chernikov int mask4, mask6; 86274b941f0SAlexander V. Chernikov 8630bce0c23SAlexander V. Chernikov mask4 = cfg->mask4; 8640bce0c23SAlexander V. Chernikov mask6 = cfg->mask6; 86574b941f0SAlexander V. Chernikov 86674b941f0SAlexander V. Chernikov if (data == NULL) 86774b941f0SAlexander V. Chernikov return (0); 86874b941f0SAlexander V. Chernikov if ((pdel = strchr(data, ' ')) == NULL) 86974b941f0SAlexander V. Chernikov return (0); 87074b941f0SAlexander V. Chernikov while (*pdel == ' ') 87174b941f0SAlexander V. Chernikov pdel++; 87274b941f0SAlexander V. Chernikov if (strncmp(pdel, "masks=", 6) != 0) 87374b941f0SAlexander V. Chernikov return (EINVAL); 87474b941f0SAlexander V. Chernikov if ((s = strchr(pdel, ' ')) != NULL) 87574b941f0SAlexander V. Chernikov *s++ = '\0'; 87674b941f0SAlexander V. Chernikov 87774b941f0SAlexander V. Chernikov pdel += 6; 87874b941f0SAlexander V. Chernikov /* Need /XX[,/YY] */ 87974b941f0SAlexander V. Chernikov if (*pdel++ != '/') 88074b941f0SAlexander V. Chernikov return (EINVAL); 88174b941f0SAlexander V. Chernikov mask4 = strtol(pdel, &pend, 10); 88274b941f0SAlexander V. Chernikov if (*pend == ',') { 88374b941f0SAlexander V. Chernikov /* ,/YY */ 88474b941f0SAlexander V. Chernikov pdel = pend + 1; 88574b941f0SAlexander V. Chernikov if (*pdel++ != '/') 88674b941f0SAlexander V. Chernikov return (EINVAL); 88774b941f0SAlexander V. Chernikov mask6 = strtol(pdel, &pend, 10); 88874b941f0SAlexander V. Chernikov if (*pend != '\0') 88974b941f0SAlexander V. Chernikov return (EINVAL); 89074b941f0SAlexander V. Chernikov } else if (*pend != '\0') 89174b941f0SAlexander V. Chernikov return (EINVAL); 89274b941f0SAlexander V. Chernikov 89374b941f0SAlexander V. Chernikov if (mask4 < 0 || mask4 > 32 || mask6 < 0 || mask6 > 128) 89474b941f0SAlexander V. Chernikov return (EINVAL); 89574b941f0SAlexander V. Chernikov 8960bce0c23SAlexander V. Chernikov cfg->mask4 = mask4; 8970bce0c23SAlexander V. Chernikov cfg->mask6 = mask6; 89874b941f0SAlexander V. Chernikov 89974b941f0SAlexander V. Chernikov return (0); 90074b941f0SAlexander V. Chernikov } 90174b941f0SAlexander V. Chernikov 90274b941f0SAlexander V. Chernikov static void 90374b941f0SAlexander V. Chernikov ta_print_chash_config(void *ta_state, struct table_info *ti, char *buf, 90474b941f0SAlexander V. Chernikov size_t bufsize) 90574b941f0SAlexander V. Chernikov { 9060bce0c23SAlexander V. Chernikov struct chash_cfg *cfg; 90774b941f0SAlexander V. Chernikov 9080bce0c23SAlexander V. Chernikov cfg = (struct chash_cfg *)ta_state; 90974b941f0SAlexander V. Chernikov 9100bce0c23SAlexander V. Chernikov if (cfg->mask4 != 32 || cfg->mask6 != 128) 91174b941f0SAlexander V. Chernikov snprintf(buf, bufsize, "%s masks=/%d,/%d", "cidr:hash", 9120bce0c23SAlexander V. Chernikov cfg->mask4, cfg->mask6); 91374b941f0SAlexander V. Chernikov else 91474b941f0SAlexander V. Chernikov snprintf(buf, bufsize, "%s", "cidr:hash"); 91574b941f0SAlexander V. Chernikov } 91674b941f0SAlexander V. Chernikov 917914bffb6SAlexander V. Chernikov static int 918914bffb6SAlexander V. Chernikov log2(uint32_t v) 919914bffb6SAlexander V. Chernikov { 920914bffb6SAlexander V. Chernikov uint32_t r; 921914bffb6SAlexander V. Chernikov 922914bffb6SAlexander V. Chernikov r = 0; 923914bffb6SAlexander V. Chernikov while (v >>= 1) 924914bffb6SAlexander V. Chernikov r++; 925914bffb6SAlexander V. Chernikov 926914bffb6SAlexander V. Chernikov return (r); 927914bffb6SAlexander V. Chernikov } 92874b941f0SAlexander V. Chernikov 92974b941f0SAlexander V. Chernikov /* 93074b941f0SAlexander V. Chernikov * New table. 93174b941f0SAlexander V. Chernikov * We assume 'data' to be either NULL or the following format: 93274b941f0SAlexander V. Chernikov * 'cidr:hash [masks=/32[,/128]]' 93374b941f0SAlexander V. Chernikov */ 93474b941f0SAlexander V. Chernikov static int 93574b941f0SAlexander V. Chernikov ta_init_chash(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti, 936914bffb6SAlexander V. Chernikov char *data, uint8_t tflags) 93774b941f0SAlexander V. Chernikov { 93874b941f0SAlexander V. Chernikov int error, i; 939914bffb6SAlexander V. Chernikov uint32_t hsize; 9400bce0c23SAlexander V. Chernikov struct chash_cfg *cfg; 94174b941f0SAlexander V. Chernikov 9420bce0c23SAlexander V. Chernikov cfg = malloc(sizeof(struct chash_cfg), M_IPFW, M_WAITOK | M_ZERO); 94374b941f0SAlexander V. Chernikov 9440bce0c23SAlexander V. Chernikov cfg->mask4 = 32; 9450bce0c23SAlexander V. Chernikov cfg->mask6 = 128; 94674b941f0SAlexander V. Chernikov 9470bce0c23SAlexander V. Chernikov if ((error = chash_parse_opts(cfg, data)) != 0) { 9480bce0c23SAlexander V. Chernikov free(cfg, M_IPFW); 94974b941f0SAlexander V. Chernikov return (error); 95074b941f0SAlexander V. Chernikov } 95174b941f0SAlexander V. Chernikov 9520bce0c23SAlexander V. Chernikov cfg->size4 = 128; 9530bce0c23SAlexander V. Chernikov cfg->size6 = 128; 95474b941f0SAlexander V. Chernikov 9550bce0c23SAlexander V. Chernikov cfg->head4 = malloc(sizeof(struct chashbhead) * cfg->size4, M_IPFW, 95674b941f0SAlexander V. Chernikov M_WAITOK | M_ZERO); 9570bce0c23SAlexander V. Chernikov cfg->head6 = malloc(sizeof(struct chashbhead) * cfg->size6, M_IPFW, 95874b941f0SAlexander V. Chernikov M_WAITOK | M_ZERO); 9590bce0c23SAlexander V. Chernikov for (i = 0; i < cfg->size4; i++) 9600bce0c23SAlexander V. Chernikov SLIST_INIT(&cfg->head4[i]); 9610bce0c23SAlexander V. Chernikov for (i = 0; i < cfg->size6; i++) 9620bce0c23SAlexander V. Chernikov SLIST_INIT(&cfg->head6[i]); 96374b941f0SAlexander V. Chernikov 96474b941f0SAlexander V. Chernikov 9650bce0c23SAlexander V. Chernikov *ta_state = cfg; 9660bce0c23SAlexander V. Chernikov ti->state = cfg->head4; 9670bce0c23SAlexander V. Chernikov ti->xstate = cfg->head6; 96874b941f0SAlexander V. Chernikov 96974b941f0SAlexander V. Chernikov /* Store data depending on v6 mask length */ 9700bce0c23SAlexander V. Chernikov hsize = log2(cfg->size4) << 8 | log2(cfg->size6); 9710bce0c23SAlexander V. Chernikov if (cfg->mask6 == 64) { 9720bce0c23SAlexander V. Chernikov ti->data = (32 - cfg->mask4) << 24 | (128 - cfg->mask6) << 16| 973914bffb6SAlexander V. Chernikov hsize; 97474b941f0SAlexander V. Chernikov ti->lookup = ta_lookup_chash_64; 9750bce0c23SAlexander V. Chernikov } else if ((cfg->mask6 % 8) == 0) { 9760bce0c23SAlexander V. Chernikov ti->data = (32 - cfg->mask4) << 24 | 9770bce0c23SAlexander V. Chernikov cfg->mask6 << 13 | hsize; 97874b941f0SAlexander V. Chernikov ti->lookup = ta_lookup_chash_aligned; 97974b941f0SAlexander V. Chernikov } else { 98074b941f0SAlexander V. Chernikov /* don't do that! */ 9810bce0c23SAlexander V. Chernikov ti->data = (32 - cfg->mask4) << 24 | 9820bce0c23SAlexander V. Chernikov cfg->mask6 << 16 | hsize; 98374b941f0SAlexander V. Chernikov ti->lookup = ta_lookup_chash_slow; 98474b941f0SAlexander V. Chernikov } 98574b941f0SAlexander V. Chernikov 98674b941f0SAlexander V. Chernikov return (0); 98774b941f0SAlexander V. Chernikov } 98874b941f0SAlexander V. Chernikov 98974b941f0SAlexander V. Chernikov static void 99074b941f0SAlexander V. Chernikov ta_destroy_chash(void *ta_state, struct table_info *ti) 99174b941f0SAlexander V. Chernikov { 9920bce0c23SAlexander V. Chernikov struct chash_cfg *cfg; 99374b941f0SAlexander V. Chernikov struct chashentry *ent, *ent_next; 99474b941f0SAlexander V. Chernikov int i; 99574b941f0SAlexander V. Chernikov 9960bce0c23SAlexander V. Chernikov cfg = (struct chash_cfg *)ta_state; 99774b941f0SAlexander V. Chernikov 9980bce0c23SAlexander V. Chernikov for (i = 0; i < cfg->size4; i++) 9990bce0c23SAlexander V. Chernikov SLIST_FOREACH_SAFE(ent, &cfg->head4[i], next, ent_next) 100074b941f0SAlexander V. Chernikov free(ent, M_IPFW_TBL); 100174b941f0SAlexander V. Chernikov 10020bce0c23SAlexander V. Chernikov for (i = 0; i < cfg->size6; i++) 10030bce0c23SAlexander V. Chernikov SLIST_FOREACH_SAFE(ent, &cfg->head6[i], next, ent_next) 100474b941f0SAlexander V. Chernikov free(ent, M_IPFW_TBL); 100574b941f0SAlexander V. Chernikov 10060bce0c23SAlexander V. Chernikov free(cfg->head4, M_IPFW); 10070bce0c23SAlexander V. Chernikov free(cfg->head6, M_IPFW); 1008ce2817b5SAlexander V. Chernikov 10090bce0c23SAlexander V. Chernikov free(cfg, M_IPFW); 101074b941f0SAlexander V. Chernikov } 101174b941f0SAlexander V. Chernikov 10125f379342SAlexander V. Chernikov static void 10135f379342SAlexander V. Chernikov ta_dump_chash_tinfo(void *ta_state, struct table_info *ti, ipfw_ta_tinfo *tinfo) 10145f379342SAlexander V. Chernikov { 10155f379342SAlexander V. Chernikov struct chash_cfg *cfg; 10165f379342SAlexander V. Chernikov 10175f379342SAlexander V. Chernikov cfg = (struct chash_cfg *)ta_state; 10185f379342SAlexander V. Chernikov 10195f379342SAlexander V. Chernikov tinfo->flags = IPFW_TATFLAGS_AFDATA | IPFW_TATFLAGS_AFITEM; 10205f379342SAlexander V. Chernikov tinfo->taclass4 = IPFW_TACLASS_HASH; 10215f379342SAlexander V. Chernikov tinfo->size4 = cfg->size4; 10225f379342SAlexander V. Chernikov tinfo->count4 = cfg->items4; 10235f379342SAlexander V. Chernikov tinfo->itemsize4 = sizeof(struct chashentry); 10245f379342SAlexander V. Chernikov tinfo->taclass6 = IPFW_TACLASS_HASH; 10255f379342SAlexander V. Chernikov tinfo->size6 = cfg->size6; 10265f379342SAlexander V. Chernikov tinfo->count6 = cfg->items6; 10275f379342SAlexander V. Chernikov tinfo->itemsize6 = sizeof(struct chashentry); 10285f379342SAlexander V. Chernikov } 10295f379342SAlexander V. Chernikov 103074b941f0SAlexander V. Chernikov static int 103174b941f0SAlexander V. Chernikov ta_dump_chash_tentry(void *ta_state, struct table_info *ti, void *e, 103274b941f0SAlexander V. Chernikov ipfw_obj_tentry *tent) 103374b941f0SAlexander V. Chernikov { 10340bce0c23SAlexander V. Chernikov struct chash_cfg *cfg; 103574b941f0SAlexander V. Chernikov struct chashentry *ent; 103674b941f0SAlexander V. Chernikov 10370bce0c23SAlexander V. Chernikov cfg = (struct chash_cfg *)ta_state; 103874b941f0SAlexander V. Chernikov ent = (struct chashentry *)e; 103974b941f0SAlexander V. Chernikov 104074b941f0SAlexander V. Chernikov if (ent->type == AF_INET) { 10410bce0c23SAlexander V. Chernikov tent->k.addr.s_addr = htonl(ent->a.a4 << (32 - cfg->mask4)); 10420bce0c23SAlexander V. Chernikov tent->masklen = cfg->mask4; 104374b941f0SAlexander V. Chernikov tent->subtype = AF_INET; 104474b941f0SAlexander V. Chernikov tent->value = ent->value; 104574b941f0SAlexander V. Chernikov #ifdef INET6 104674b941f0SAlexander V. Chernikov } else { 104774b941f0SAlexander V. Chernikov memcpy(&tent->k, &ent->a.a6, sizeof(struct in6_addr)); 10480bce0c23SAlexander V. Chernikov tent->masklen = cfg->mask6; 104974b941f0SAlexander V. Chernikov tent->subtype = AF_INET6; 105074b941f0SAlexander V. Chernikov tent->value = ent->value; 105174b941f0SAlexander V. Chernikov #endif 105274b941f0SAlexander V. Chernikov } 105374b941f0SAlexander V. Chernikov 105474b941f0SAlexander V. Chernikov return (0); 105574b941f0SAlexander V. Chernikov } 105674b941f0SAlexander V. Chernikov 1057ce2817b5SAlexander V. Chernikov static uint32_t 1058ce2817b5SAlexander V. Chernikov hash_ent(struct chashentry *ent, int af, int mlen, uint32_t size) 1059ce2817b5SAlexander V. Chernikov { 1060ce2817b5SAlexander V. Chernikov uint32_t hash; 1061ce2817b5SAlexander V. Chernikov 1062ce2817b5SAlexander V. Chernikov if (af == AF_INET) { 1063ce2817b5SAlexander V. Chernikov hash = hash_ip(ent->a.a4, size); 1064ce2817b5SAlexander V. Chernikov } else { 1065ce2817b5SAlexander V. Chernikov if (mlen == 64) 1066ce2817b5SAlexander V. Chernikov hash = hash_ip64(&ent->a.a6, size); 1067ce2817b5SAlexander V. Chernikov else 1068ce2817b5SAlexander V. Chernikov hash = hash_ip6(&ent->a.a6, size); 1069ce2817b5SAlexander V. Chernikov } 1070ce2817b5SAlexander V. Chernikov 1071ce2817b5SAlexander V. Chernikov return (hash); 1072ce2817b5SAlexander V. Chernikov } 1073ce2817b5SAlexander V. Chernikov 1074ce2817b5SAlexander V. Chernikov static int 1075ce2817b5SAlexander V. Chernikov tei_to_chash_ent(struct tentry_info *tei, struct chashentry *ent) 1076ce2817b5SAlexander V. Chernikov { 1077ce2817b5SAlexander V. Chernikov struct in6_addr mask6; 1078ce2817b5SAlexander V. Chernikov int mlen; 1079ce2817b5SAlexander V. Chernikov 1080ce2817b5SAlexander V. Chernikov 1081ce2817b5SAlexander V. Chernikov mlen = tei->masklen; 1082ce2817b5SAlexander V. Chernikov 1083ce2817b5SAlexander V. Chernikov if (tei->subtype == AF_INET) { 1084ce2817b5SAlexander V. Chernikov #ifdef INET 1085ce2817b5SAlexander V. Chernikov if (mlen > 32) 1086ce2817b5SAlexander V. Chernikov return (EINVAL); 1087ce2817b5SAlexander V. Chernikov ent->type = AF_INET; 1088ce2817b5SAlexander V. Chernikov 1089ce2817b5SAlexander V. Chernikov /* Calculate masked address */ 1090ce2817b5SAlexander V. Chernikov ent->a.a4 = ntohl(*((in_addr_t *)tei->paddr)) >> (32 - mlen); 1091ce2817b5SAlexander V. Chernikov #endif 1092ce2817b5SAlexander V. Chernikov #ifdef INET6 1093ce2817b5SAlexander V. Chernikov } else if (tei->subtype == AF_INET6) { 1094ce2817b5SAlexander V. Chernikov /* IPv6 case */ 1095ce2817b5SAlexander V. Chernikov if (mlen > 128) 1096ce2817b5SAlexander V. Chernikov return (EINVAL); 1097ce2817b5SAlexander V. Chernikov ent->type = AF_INET6; 1098ce2817b5SAlexander V. Chernikov 1099ce2817b5SAlexander V. Chernikov ipv6_writemask(&mask6, mlen); 1100ce2817b5SAlexander V. Chernikov memcpy(&ent->a.a6, tei->paddr, sizeof(struct in6_addr)); 1101ce2817b5SAlexander V. Chernikov APPLY_MASK(&ent->a.a6, &mask6); 1102ce2817b5SAlexander V. Chernikov #endif 1103ce2817b5SAlexander V. Chernikov } else { 1104ce2817b5SAlexander V. Chernikov /* Unknown CIDR type */ 1105ce2817b5SAlexander V. Chernikov return (EINVAL); 1106ce2817b5SAlexander V. Chernikov } 1107ce2817b5SAlexander V. Chernikov ent->value = tei->value; 1108ce2817b5SAlexander V. Chernikov 1109ce2817b5SAlexander V. Chernikov return (0); 1110ce2817b5SAlexander V. Chernikov } 1111ce2817b5SAlexander V. Chernikov 111274b941f0SAlexander V. Chernikov static int 1113914bffb6SAlexander V. Chernikov ta_find_chash_tentry(void *ta_state, struct table_info *ti, 1114914bffb6SAlexander V. Chernikov ipfw_obj_tentry *tent) 111574b941f0SAlexander V. Chernikov { 11160bce0c23SAlexander V. Chernikov struct chash_cfg *cfg; 1117ce2817b5SAlexander V. Chernikov struct chashbhead *head; 1118ce2817b5SAlexander V. Chernikov struct chashentry ent, *tmp; 1119ce2817b5SAlexander V. Chernikov struct tentry_info tei; 1120ce2817b5SAlexander V. Chernikov int error; 1121ce2817b5SAlexander V. Chernikov uint32_t hash; 112274b941f0SAlexander V. Chernikov 11230bce0c23SAlexander V. Chernikov cfg = (struct chash_cfg *)ta_state; 1124ce2817b5SAlexander V. Chernikov 1125ce2817b5SAlexander V. Chernikov memset(&ent, 0, sizeof(ent)); 1126ce2817b5SAlexander V. Chernikov memset(&tei, 0, sizeof(tei)); 1127ce2817b5SAlexander V. Chernikov 1128914bffb6SAlexander V. Chernikov if (tent->subtype == AF_INET) { 1129914bffb6SAlexander V. Chernikov tei.paddr = &tent->k.addr; 11300bce0c23SAlexander V. Chernikov tei.masklen = cfg->mask4; 1131ce2817b5SAlexander V. Chernikov tei.subtype = AF_INET; 113274b941f0SAlexander V. Chernikov 1133ce2817b5SAlexander V. Chernikov if ((error = tei_to_chash_ent(&tei, &ent)) != 0) 1134ce2817b5SAlexander V. Chernikov return (error); 1135ce2817b5SAlexander V. Chernikov 11360bce0c23SAlexander V. Chernikov head = cfg->head4; 11370bce0c23SAlexander V. Chernikov hash = hash_ent(&ent, AF_INET, cfg->mask4, cfg->size4); 1138ce2817b5SAlexander V. Chernikov /* Check for existence */ 1139ce2817b5SAlexander V. Chernikov SLIST_FOREACH(tmp, &head[hash], next) { 1140ce2817b5SAlexander V. Chernikov if (tmp->a.a4 != ent.a.a4) 1141ce2817b5SAlexander V. Chernikov continue; 1142ce2817b5SAlexander V. Chernikov 1143ce2817b5SAlexander V. Chernikov ta_dump_chash_tentry(ta_state, ti, tmp, tent); 114474b941f0SAlexander V. Chernikov return (0); 114574b941f0SAlexander V. Chernikov } 1146ce2817b5SAlexander V. Chernikov } else { 1147914bffb6SAlexander V. Chernikov tei.paddr = &tent->k.addr6; 11480bce0c23SAlexander V. Chernikov tei.masklen = cfg->mask6; 1149ce2817b5SAlexander V. Chernikov tei.subtype = AF_INET6; 1150ce2817b5SAlexander V. Chernikov 1151ce2817b5SAlexander V. Chernikov if ((error = tei_to_chash_ent(&tei, &ent)) != 0) 1152ce2817b5SAlexander V. Chernikov return (error); 1153ce2817b5SAlexander V. Chernikov 11540bce0c23SAlexander V. Chernikov head = cfg->head6; 11550bce0c23SAlexander V. Chernikov hash = hash_ent(&ent, AF_INET6, cfg->mask6, cfg->size6); 1156ce2817b5SAlexander V. Chernikov /* Check for existence */ 1157ce2817b5SAlexander V. Chernikov SLIST_FOREACH(tmp, &head[hash], next) { 1158ce2817b5SAlexander V. Chernikov if (memcmp(&tmp->a.a6, &ent.a.a6, 16) != 0) 1159ce2817b5SAlexander V. Chernikov continue; 1160ce2817b5SAlexander V. Chernikov ta_dump_chash_tentry(ta_state, ti, tmp, tent); 1161ce2817b5SAlexander V. Chernikov return (0); 1162ce2817b5SAlexander V. Chernikov } 1163ce2817b5SAlexander V. Chernikov } 1164ce2817b5SAlexander V. Chernikov 116574b941f0SAlexander V. Chernikov return (ENOENT); 116674b941f0SAlexander V. Chernikov } 116774b941f0SAlexander V. Chernikov 116874b941f0SAlexander V. Chernikov static void 116974b941f0SAlexander V. Chernikov ta_foreach_chash(void *ta_state, struct table_info *ti, ta_foreach_f *f, 117074b941f0SAlexander V. Chernikov void *arg) 117174b941f0SAlexander V. Chernikov { 11720bce0c23SAlexander V. Chernikov struct chash_cfg *cfg; 117374b941f0SAlexander V. Chernikov struct chashentry *ent, *ent_next; 117474b941f0SAlexander V. Chernikov int i; 117574b941f0SAlexander V. Chernikov 11760bce0c23SAlexander V. Chernikov cfg = (struct chash_cfg *)ta_state; 117774b941f0SAlexander V. Chernikov 11780bce0c23SAlexander V. Chernikov for (i = 0; i < cfg->size4; i++) 11790bce0c23SAlexander V. Chernikov SLIST_FOREACH_SAFE(ent, &cfg->head4[i], next, ent_next) 118074b941f0SAlexander V. Chernikov f(ent, arg); 118174b941f0SAlexander V. Chernikov 11820bce0c23SAlexander V. Chernikov for (i = 0; i < cfg->size6; i++) 11830bce0c23SAlexander V. Chernikov SLIST_FOREACH_SAFE(ent, &cfg->head6[i], next, ent_next) 118474b941f0SAlexander V. Chernikov f(ent, arg); 118574b941f0SAlexander V. Chernikov } 118674b941f0SAlexander V. Chernikov 118774b941f0SAlexander V. Chernikov static int 118874b941f0SAlexander V. Chernikov ta_prepare_add_chash(struct ip_fw_chain *ch, struct tentry_info *tei, 118974b941f0SAlexander V. Chernikov void *ta_buf) 119074b941f0SAlexander V. Chernikov { 119174b941f0SAlexander V. Chernikov struct ta_buf_chash *tb; 119274b941f0SAlexander V. Chernikov struct chashentry *ent; 1193ce2817b5SAlexander V. Chernikov int error; 119474b941f0SAlexander V. Chernikov 119574b941f0SAlexander V. Chernikov tb = (struct ta_buf_chash *)ta_buf; 119674b941f0SAlexander V. Chernikov 119774b941f0SAlexander V. Chernikov ent = malloc(sizeof(*ent), M_IPFW_TBL, M_WAITOK | M_ZERO); 119874b941f0SAlexander V. Chernikov 1199ce2817b5SAlexander V. Chernikov error = tei_to_chash_ent(tei, ent); 1200ce2817b5SAlexander V. Chernikov if (error != 0) { 1201ce2817b5SAlexander V. Chernikov free(ent, M_IPFW_TBL); 1202ce2817b5SAlexander V. Chernikov return (error); 120374b941f0SAlexander V. Chernikov } 1204ce2817b5SAlexander V. Chernikov tb->ent_ptr = ent; 120574b941f0SAlexander V. Chernikov 120674b941f0SAlexander V. Chernikov return (0); 120774b941f0SAlexander V. Chernikov } 120874b941f0SAlexander V. Chernikov 120974b941f0SAlexander V. Chernikov static int 121074b941f0SAlexander V. Chernikov ta_add_chash(void *ta_state, struct table_info *ti, struct tentry_info *tei, 1211b6ee846eSAlexander V. Chernikov void *ta_buf, uint32_t *pnum) 121274b941f0SAlexander V. Chernikov { 12130bce0c23SAlexander V. Chernikov struct chash_cfg *cfg; 121474b941f0SAlexander V. Chernikov struct chashbhead *head; 121574b941f0SAlexander V. Chernikov struct chashentry *ent, *tmp; 121674b941f0SAlexander V. Chernikov struct ta_buf_chash *tb; 121774b941f0SAlexander V. Chernikov int exists; 1218648e8380SAlexander V. Chernikov uint32_t hash, value; 121974b941f0SAlexander V. Chernikov 12200bce0c23SAlexander V. Chernikov cfg = (struct chash_cfg *)ta_state; 122174b941f0SAlexander V. Chernikov tb = (struct ta_buf_chash *)ta_buf; 122274b941f0SAlexander V. Chernikov ent = (struct chashentry *)tb->ent_ptr; 122374b941f0SAlexander V. Chernikov hash = 0; 122474b941f0SAlexander V. Chernikov exists = 0; 122574b941f0SAlexander V. Chernikov 122674b941f0SAlexander V. Chernikov if (tei->subtype == AF_INET) { 12270bce0c23SAlexander V. Chernikov if (tei->masklen != cfg->mask4) 122874b941f0SAlexander V. Chernikov return (EINVAL); 12290bce0c23SAlexander V. Chernikov head = cfg->head4; 12300bce0c23SAlexander V. Chernikov hash = hash_ent(ent, AF_INET, cfg->mask4, cfg->size4); 1231ce2817b5SAlexander V. Chernikov 123274b941f0SAlexander V. Chernikov /* Check for existence */ 123374b941f0SAlexander V. Chernikov SLIST_FOREACH(tmp, &head[hash], next) { 123474b941f0SAlexander V. Chernikov if (tmp->a.a4 == ent->a.a4) { 123574b941f0SAlexander V. Chernikov exists = 1; 123674b941f0SAlexander V. Chernikov break; 123774b941f0SAlexander V. Chernikov } 123874b941f0SAlexander V. Chernikov } 123974b941f0SAlexander V. Chernikov } else { 12400bce0c23SAlexander V. Chernikov if (tei->masklen != cfg->mask6) 124174b941f0SAlexander V. Chernikov return (EINVAL); 12420bce0c23SAlexander V. Chernikov head = cfg->head6; 12430bce0c23SAlexander V. Chernikov hash = hash_ent(ent, AF_INET6, cfg->mask6, cfg->size6); 124474b941f0SAlexander V. Chernikov /* Check for existence */ 124574b941f0SAlexander V. Chernikov SLIST_FOREACH(tmp, &head[hash], next) { 1246ce2817b5SAlexander V. Chernikov if (memcmp(&tmp->a.a6, &ent->a.a6, 16) == 0) { 124774b941f0SAlexander V. Chernikov exists = 1; 124874b941f0SAlexander V. Chernikov break; 124974b941f0SAlexander V. Chernikov } 125074b941f0SAlexander V. Chernikov } 125174b941f0SAlexander V. Chernikov } 125274b941f0SAlexander V. Chernikov 125374b941f0SAlexander V. Chernikov if (exists == 1) { 125474b941f0SAlexander V. Chernikov if ((tei->flags & TEI_FLAGS_UPDATE) == 0) 125574b941f0SAlexander V. Chernikov return (EEXIST); 125674b941f0SAlexander V. Chernikov /* Record already exists. Update value if we're asked to */ 1257648e8380SAlexander V. Chernikov value = tmp->value; 125874b941f0SAlexander V. Chernikov tmp->value = tei->value; 1259648e8380SAlexander V. Chernikov tei->value = value; 126074b941f0SAlexander V. Chernikov /* Indicate that update has happened instead of addition */ 126174b941f0SAlexander V. Chernikov tei->flags |= TEI_FLAGS_UPDATED; 126274b941f0SAlexander V. Chernikov *pnum = 0; 126374b941f0SAlexander V. Chernikov } else { 12644c0c07a5SAlexander V. Chernikov if ((tei->flags & TEI_FLAGS_DONTADD) != 0) 12654c0c07a5SAlexander V. Chernikov return (EFBIG); 126674b941f0SAlexander V. Chernikov SLIST_INSERT_HEAD(&head[hash], ent, next); 126774b941f0SAlexander V. Chernikov tb->ent_ptr = NULL; 126874b941f0SAlexander V. Chernikov *pnum = 1; 1269ce2817b5SAlexander V. Chernikov 1270b6ee846eSAlexander V. Chernikov /* Update counters */ 1271b6ee846eSAlexander V. Chernikov if (tei->subtype == AF_INET) 12720bce0c23SAlexander V. Chernikov cfg->items4++; 1273b6ee846eSAlexander V. Chernikov else 12740bce0c23SAlexander V. Chernikov cfg->items6++; 127574b941f0SAlexander V. Chernikov } 127674b941f0SAlexander V. Chernikov 127774b941f0SAlexander V. Chernikov return (0); 127874b941f0SAlexander V. Chernikov } 127974b941f0SAlexander V. Chernikov 128074b941f0SAlexander V. Chernikov static int 128174b941f0SAlexander V. Chernikov ta_prepare_del_chash(struct ip_fw_chain *ch, struct tentry_info *tei, 128274b941f0SAlexander V. Chernikov void *ta_buf) 128374b941f0SAlexander V. Chernikov { 128474b941f0SAlexander V. Chernikov struct ta_buf_chash *tb; 128574b941f0SAlexander V. Chernikov 128674b941f0SAlexander V. Chernikov tb = (struct ta_buf_chash *)ta_buf; 128774b941f0SAlexander V. Chernikov 1288ce2817b5SAlexander V. Chernikov return (tei_to_chash_ent(tei, &tb->ent)); 128974b941f0SAlexander V. Chernikov } 129074b941f0SAlexander V. Chernikov 129174b941f0SAlexander V. Chernikov static int 129274b941f0SAlexander V. Chernikov ta_del_chash(void *ta_state, struct table_info *ti, struct tentry_info *tei, 1293b6ee846eSAlexander V. Chernikov void *ta_buf, uint32_t *pnum) 129474b941f0SAlexander V. Chernikov { 12950bce0c23SAlexander V. Chernikov struct chash_cfg *cfg; 129674b941f0SAlexander V. Chernikov struct chashbhead *head; 12970bce0c23SAlexander V. Chernikov struct chashentry *tmp, *tmp_next, *ent; 129874b941f0SAlexander V. Chernikov struct ta_buf_chash *tb; 129974b941f0SAlexander V. Chernikov uint32_t hash; 130074b941f0SAlexander V. Chernikov 13010bce0c23SAlexander V. Chernikov cfg = (struct chash_cfg *)ta_state; 130274b941f0SAlexander V. Chernikov tb = (struct ta_buf_chash *)ta_buf; 13030bce0c23SAlexander V. Chernikov ent = &tb->ent; 130474b941f0SAlexander V. Chernikov 130574b941f0SAlexander V. Chernikov if (tei->subtype == AF_INET) { 13060bce0c23SAlexander V. Chernikov if (tei->masklen != cfg->mask4) 130774b941f0SAlexander V. Chernikov return (EINVAL); 13080bce0c23SAlexander V. Chernikov head = cfg->head4; 13090bce0c23SAlexander V. Chernikov hash = hash_ent(ent, AF_INET, cfg->mask4, cfg->size4); 131074b941f0SAlexander V. Chernikov 13110bce0c23SAlexander V. Chernikov SLIST_FOREACH_SAFE(tmp, &head[hash], next, tmp_next) { 13120bce0c23SAlexander V. Chernikov if (tmp->a.a4 != ent->a.a4) 1313648e8380SAlexander V. Chernikov continue; 1314648e8380SAlexander V. Chernikov 13150bce0c23SAlexander V. Chernikov SLIST_REMOVE(&head[hash], tmp, chashentry, next); 13160bce0c23SAlexander V. Chernikov cfg->items4--; 13170bce0c23SAlexander V. Chernikov tb->ent_ptr = tmp; 13180bce0c23SAlexander V. Chernikov tei->value = tmp->value; 1319648e8380SAlexander V. Chernikov *pnum = 1; 132074b941f0SAlexander V. Chernikov return (0); 132174b941f0SAlexander V. Chernikov } 132274b941f0SAlexander V. Chernikov } else { 13230bce0c23SAlexander V. Chernikov if (tei->masklen != cfg->mask6) 132474b941f0SAlexander V. Chernikov return (EINVAL); 13250bce0c23SAlexander V. Chernikov head = cfg->head6; 13260bce0c23SAlexander V. Chernikov hash = hash_ent(ent, AF_INET6, cfg->mask6, cfg->size6); 13270bce0c23SAlexander V. Chernikov SLIST_FOREACH_SAFE(tmp, &head[hash], next, tmp_next) { 13280bce0c23SAlexander V. Chernikov if (memcmp(&tmp->a.a6, &ent->a.a6, 16) != 0) 1329648e8380SAlexander V. Chernikov continue; 1330648e8380SAlexander V. Chernikov 13310bce0c23SAlexander V. Chernikov SLIST_REMOVE(&head[hash], tmp, chashentry, next); 13320bce0c23SAlexander V. Chernikov cfg->items6--; 13330bce0c23SAlexander V. Chernikov tb->ent_ptr = tmp; 13340bce0c23SAlexander V. Chernikov tei->value = tmp->value; 133574b941f0SAlexander V. Chernikov *pnum = 1; 133674b941f0SAlexander V. Chernikov return (0); 133774b941f0SAlexander V. Chernikov } 133874b941f0SAlexander V. Chernikov } 133974b941f0SAlexander V. Chernikov 134074b941f0SAlexander V. Chernikov return (ENOENT); 134174b941f0SAlexander V. Chernikov } 134274b941f0SAlexander V. Chernikov 134374b941f0SAlexander V. Chernikov static void 134474b941f0SAlexander V. Chernikov ta_flush_chash_entry(struct ip_fw_chain *ch, struct tentry_info *tei, 134574b941f0SAlexander V. Chernikov void *ta_buf) 134674b941f0SAlexander V. Chernikov { 134774b941f0SAlexander V. Chernikov struct ta_buf_chash *tb; 134874b941f0SAlexander V. Chernikov 134974b941f0SAlexander V. Chernikov tb = (struct ta_buf_chash *)ta_buf; 135074b941f0SAlexander V. Chernikov 135174b941f0SAlexander V. Chernikov if (tb->ent_ptr != NULL) 135274b941f0SAlexander V. Chernikov free(tb->ent_ptr, M_IPFW_TBL); 135374b941f0SAlexander V. Chernikov } 135474b941f0SAlexander V. Chernikov 1355ce2817b5SAlexander V. Chernikov /* 1356ce2817b5SAlexander V. Chernikov * Hash growing callbacks. 1357ce2817b5SAlexander V. Chernikov */ 1358ce2817b5SAlexander V. Chernikov 1359b6ee846eSAlexander V. Chernikov static int 1360b6ee846eSAlexander V. Chernikov ta_has_space_chash(void *ta_state, struct table_info *ti, uint32_t count, 1361b6ee846eSAlexander V. Chernikov uint64_t *pflags) 1362b6ee846eSAlexander V. Chernikov { 1363b6ee846eSAlexander V. Chernikov struct chash_cfg *cfg; 1364b6ee846eSAlexander V. Chernikov uint64_t data; 1365b6ee846eSAlexander V. Chernikov 1366b6ee846eSAlexander V. Chernikov /* 1367b6ee846eSAlexander V. Chernikov * Since we don't know exact number of IPv4/IPv6 records in @count, 1368b6ee846eSAlexander V. Chernikov * ignore non-zero @count value at all. Check current hash sizes 1369b6ee846eSAlexander V. Chernikov * and return appropriate data. 1370b6ee846eSAlexander V. Chernikov */ 1371b6ee846eSAlexander V. Chernikov 1372b6ee846eSAlexander V. Chernikov cfg = (struct chash_cfg *)ta_state; 1373b6ee846eSAlexander V. Chernikov 1374b6ee846eSAlexander V. Chernikov data = 0; 1375b6ee846eSAlexander V. Chernikov if (cfg->items4 > cfg->size4 && cfg->size4 < 65536) 1376b6ee846eSAlexander V. Chernikov data |= (cfg->size4 * 2) << 16; 1377b6ee846eSAlexander V. Chernikov if (cfg->items6 > cfg->size6 && cfg->size6 < 65536) 1378b6ee846eSAlexander V. Chernikov data |= cfg->size6 * 2; 1379b6ee846eSAlexander V. Chernikov 1380b6ee846eSAlexander V. Chernikov if (data != 0) { 1381b6ee846eSAlexander V. Chernikov *pflags = data; 1382b6ee846eSAlexander V. Chernikov return (0); 1383b6ee846eSAlexander V. Chernikov } 1384b6ee846eSAlexander V. Chernikov 1385b6ee846eSAlexander V. Chernikov return (1); 1386b6ee846eSAlexander V. Chernikov } 1387b6ee846eSAlexander V. Chernikov 1388ce2817b5SAlexander V. Chernikov /* 1389ce2817b5SAlexander V. Chernikov * Allocate new, larger chash. 1390ce2817b5SAlexander V. Chernikov */ 1391ce2817b5SAlexander V. Chernikov static int 1392ce2817b5SAlexander V. Chernikov ta_prepare_mod_chash(void *ta_buf, uint64_t *pflags) 1393ce2817b5SAlexander V. Chernikov { 1394ce2817b5SAlexander V. Chernikov struct mod_item *mi; 1395ce2817b5SAlexander V. Chernikov struct chashbhead *head; 1396ce2817b5SAlexander V. Chernikov int i; 1397ce2817b5SAlexander V. Chernikov 1398ce2817b5SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 1399ce2817b5SAlexander V. Chernikov 1400ce2817b5SAlexander V. Chernikov memset(mi, 0, sizeof(struct mod_item)); 1401b6ee846eSAlexander V. Chernikov mi->size = (*pflags >> 16) & 0xFFFF; 1402b6ee846eSAlexander V. Chernikov mi->size6 = *pflags & 0xFFFF; 1403b6ee846eSAlexander V. Chernikov if (mi->size > 0) { 1404b6ee846eSAlexander V. Chernikov head = malloc(sizeof(struct chashbhead) * mi->size, 1405b6ee846eSAlexander V. Chernikov M_IPFW, M_WAITOK | M_ZERO); 1406ce2817b5SAlexander V. Chernikov for (i = 0; i < mi->size; i++) 1407ce2817b5SAlexander V. Chernikov SLIST_INIT(&head[i]); 1408ce2817b5SAlexander V. Chernikov mi->main_ptr = head; 1409b6ee846eSAlexander V. Chernikov } 1410b6ee846eSAlexander V. Chernikov 1411b6ee846eSAlexander V. Chernikov if (mi->size6 > 0) { 1412b6ee846eSAlexander V. Chernikov head = malloc(sizeof(struct chashbhead) * mi->size6, 1413b6ee846eSAlexander V. Chernikov M_IPFW, M_WAITOK | M_ZERO); 1414b6ee846eSAlexander V. Chernikov for (i = 0; i < mi->size6; i++) 1415b6ee846eSAlexander V. Chernikov SLIST_INIT(&head[i]); 1416b6ee846eSAlexander V. Chernikov mi->main_ptr6 = head; 1417b6ee846eSAlexander V. Chernikov } 1418ce2817b5SAlexander V. Chernikov 1419ce2817b5SAlexander V. Chernikov return (0); 1420ce2817b5SAlexander V. Chernikov } 1421ce2817b5SAlexander V. Chernikov 1422ce2817b5SAlexander V. Chernikov /* 1423ce2817b5SAlexander V. Chernikov * Copy data from old runtime array to new one. 1424ce2817b5SAlexander V. Chernikov */ 1425ce2817b5SAlexander V. Chernikov static int 1426ce2817b5SAlexander V. Chernikov ta_fill_mod_chash(void *ta_state, struct table_info *ti, void *ta_buf, 1427ce2817b5SAlexander V. Chernikov uint64_t *pflags) 1428ce2817b5SAlexander V. Chernikov { 1429ce2817b5SAlexander V. Chernikov 1430ce2817b5SAlexander V. Chernikov /* In is not possible to do rehash if we're not holidng WLOCK. */ 1431ce2817b5SAlexander V. Chernikov return (0); 1432ce2817b5SAlexander V. Chernikov } 1433ce2817b5SAlexander V. Chernikov 1434ce2817b5SAlexander V. Chernikov /* 1435ce2817b5SAlexander V. Chernikov * Switch old & new arrays. 1436ce2817b5SAlexander V. Chernikov */ 1437ce2817b5SAlexander V. Chernikov static int 1438ce2817b5SAlexander V. Chernikov ta_modify_chash(void *ta_state, struct table_info *ti, void *ta_buf, 1439ce2817b5SAlexander V. Chernikov uint64_t pflags) 1440ce2817b5SAlexander V. Chernikov { 1441ce2817b5SAlexander V. Chernikov struct mod_item *mi; 1442b6ee846eSAlexander V. Chernikov struct chash_cfg *cfg; 1443ce2817b5SAlexander V. Chernikov struct chashbhead *old_head, *new_head; 1444ce2817b5SAlexander V. Chernikov struct chashentry *ent, *ent_next; 1445ce2817b5SAlexander V. Chernikov int af, i, mlen; 1446ce2817b5SAlexander V. Chernikov uint32_t nhash; 1447b6ee846eSAlexander V. Chernikov size_t old_size, new_size; 1448ce2817b5SAlexander V. Chernikov 1449ce2817b5SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 1450b6ee846eSAlexander V. Chernikov cfg = (struct chash_cfg *)ta_state; 1451ce2817b5SAlexander V. Chernikov 1452ce2817b5SAlexander V. Chernikov /* Check which hash we need to grow and do we still need that */ 1453b6ee846eSAlexander V. Chernikov if (mi->size > 0 && cfg->size4 < mi->size) { 1454ce2817b5SAlexander V. Chernikov new_head = (struct chashbhead *)mi->main_ptr; 1455b6ee846eSAlexander V. Chernikov new_size = mi->size; 1456b6ee846eSAlexander V. Chernikov old_size = cfg->size4; 1457b6ee846eSAlexander V. Chernikov old_head = ti->state; 1458b6ee846eSAlexander V. Chernikov mlen = cfg->mask4; 1459b6ee846eSAlexander V. Chernikov af = AF_INET; 1460b6ee846eSAlexander V. Chernikov 1461ce2817b5SAlexander V. Chernikov for (i = 0; i < old_size; i++) { 1462ce2817b5SAlexander V. Chernikov SLIST_FOREACH_SAFE(ent, &old_head[i], next, ent_next) { 1463b6ee846eSAlexander V. Chernikov nhash = hash_ent(ent, af, mlen, new_size); 1464ce2817b5SAlexander V. Chernikov SLIST_INSERT_HEAD(&new_head[nhash], ent, next); 1465ce2817b5SAlexander V. Chernikov } 1466ce2817b5SAlexander V. Chernikov } 1467ce2817b5SAlexander V. Chernikov 1468ce2817b5SAlexander V. Chernikov ti->state = new_head; 1469b6ee846eSAlexander V. Chernikov cfg->head4 = new_head; 1470b6ee846eSAlexander V. Chernikov cfg->size4 = mi->size; 1471b6ee846eSAlexander V. Chernikov mi->main_ptr = old_head; 1472ce2817b5SAlexander V. Chernikov } 1473ce2817b5SAlexander V. Chernikov 1474b6ee846eSAlexander V. Chernikov if (mi->size6 > 0 && cfg->size6 < mi->size6) { 1475b6ee846eSAlexander V. Chernikov new_head = (struct chashbhead *)mi->main_ptr6; 1476b6ee846eSAlexander V. Chernikov new_size = mi->size6; 1477b6ee846eSAlexander V. Chernikov old_size = cfg->size6; 1478b6ee846eSAlexander V. Chernikov old_head = ti->xstate; 1479b6ee846eSAlexander V. Chernikov mlen = cfg->mask6; 1480b6ee846eSAlexander V. Chernikov af = AF_INET6; 1481914bffb6SAlexander V. Chernikov 1482b6ee846eSAlexander V. Chernikov for (i = 0; i < old_size; i++) { 1483b6ee846eSAlexander V. Chernikov SLIST_FOREACH_SAFE(ent, &old_head[i], next, ent_next) { 1484b6ee846eSAlexander V. Chernikov nhash = hash_ent(ent, af, mlen, new_size); 1485b6ee846eSAlexander V. Chernikov SLIST_INSERT_HEAD(&new_head[nhash], ent, next); 1486b6ee846eSAlexander V. Chernikov } 1487b6ee846eSAlexander V. Chernikov } 1488b6ee846eSAlexander V. Chernikov 1489b6ee846eSAlexander V. Chernikov ti->xstate = new_head; 1490b6ee846eSAlexander V. Chernikov cfg->head6 = new_head; 1491b6ee846eSAlexander V. Chernikov cfg->size6 = mi->size6; 1492b6ee846eSAlexander V. Chernikov mi->main_ptr6 = old_head; 1493b6ee846eSAlexander V. Chernikov } 1494b6ee846eSAlexander V. Chernikov 1495b6ee846eSAlexander V. Chernikov /* Update lower 32 bits with new values */ 1496b6ee846eSAlexander V. Chernikov ti->data &= 0xFFFFFFFF00000000; 1497b6ee846eSAlexander V. Chernikov ti->data |= log2(cfg->size4) << 8 | log2(cfg->size6); 1498ce2817b5SAlexander V. Chernikov 1499ce2817b5SAlexander V. Chernikov return (0); 1500ce2817b5SAlexander V. Chernikov } 1501ce2817b5SAlexander V. Chernikov 1502ce2817b5SAlexander V. Chernikov /* 1503ce2817b5SAlexander V. Chernikov * Free unneded array. 1504ce2817b5SAlexander V. Chernikov */ 1505ce2817b5SAlexander V. Chernikov static void 1506ce2817b5SAlexander V. Chernikov ta_flush_mod_chash(void *ta_buf) 1507ce2817b5SAlexander V. Chernikov { 1508ce2817b5SAlexander V. Chernikov struct mod_item *mi; 1509ce2817b5SAlexander V. Chernikov 1510ce2817b5SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 1511ce2817b5SAlexander V. Chernikov if (mi->main_ptr != NULL) 1512ce2817b5SAlexander V. Chernikov free(mi->main_ptr, M_IPFW); 1513b6ee846eSAlexander V. Chernikov if (mi->main_ptr6 != NULL) 1514b6ee846eSAlexander V. Chernikov free(mi->main_ptr6, M_IPFW); 1515ce2817b5SAlexander V. Chernikov } 1516ce2817b5SAlexander V. Chernikov 151774b941f0SAlexander V. Chernikov struct table_algo cidr_hash = { 151874b941f0SAlexander V. Chernikov .name = "cidr:hash", 15199d099b4fSAlexander V. Chernikov .type = IPFW_TABLE_CIDR, 152057a1cf95SAlexander V. Chernikov .ta_buf_size = sizeof(struct ta_buf_chash), 152174b941f0SAlexander V. Chernikov .init = ta_init_chash, 152274b941f0SAlexander V. Chernikov .destroy = ta_destroy_chash, 152374b941f0SAlexander V. Chernikov .prepare_add = ta_prepare_add_chash, 152474b941f0SAlexander V. Chernikov .prepare_del = ta_prepare_del_chash, 152574b941f0SAlexander V. Chernikov .add = ta_add_chash, 152674b941f0SAlexander V. Chernikov .del = ta_del_chash, 152774b941f0SAlexander V. Chernikov .flush_entry = ta_flush_chash_entry, 152874b941f0SAlexander V. Chernikov .foreach = ta_foreach_chash, 152974b941f0SAlexander V. Chernikov .dump_tentry = ta_dump_chash_tentry, 153074b941f0SAlexander V. Chernikov .find_tentry = ta_find_chash_tentry, 153174b941f0SAlexander V. Chernikov .print_config = ta_print_chash_config, 15325f379342SAlexander V. Chernikov .dump_tinfo = ta_dump_chash_tinfo, 1533b6ee846eSAlexander V. Chernikov .has_space = ta_has_space_chash, 1534ce2817b5SAlexander V. Chernikov .prepare_mod = ta_prepare_mod_chash, 1535ce2817b5SAlexander V. Chernikov .fill_mod = ta_fill_mod_chash, 1536ce2817b5SAlexander V. Chernikov .modify = ta_modify_chash, 1537ce2817b5SAlexander V. Chernikov .flush_mod = ta_flush_mod_chash, 153874b941f0SAlexander V. Chernikov }; 153974b941f0SAlexander V. Chernikov 154074b941f0SAlexander V. Chernikov 154174b941f0SAlexander V. Chernikov /* 154268394ec8SAlexander V. Chernikov * Iface table cmds. 154368394ec8SAlexander V. Chernikov * 154468394ec8SAlexander V. Chernikov * Implementation: 154568394ec8SAlexander V. Chernikov * 154668394ec8SAlexander V. Chernikov * Runtime part: 154768394ec8SAlexander V. Chernikov * - sorted array of "struct ifidx" pointed by ti->state. 1548b23d5de9SAlexander V. Chernikov * Array is allocated with rounding up to IFIDX_CHUNK. Only existing 154968394ec8SAlexander V. Chernikov * interfaces are stored in array, however its allocated size is 155068394ec8SAlexander V. Chernikov * sufficient to hold all table records if needed. 155168394ec8SAlexander V. Chernikov * - current array size is stored in ti->data 155268394ec8SAlexander V. Chernikov * 155368394ec8SAlexander V. Chernikov * Table data: 155468394ec8SAlexander V. Chernikov * - "struct iftable_cfg" is allocated to store table state (ta_state). 155568394ec8SAlexander V. Chernikov * - All table records are stored inside namedobj instance. 15569f7d47b0SAlexander V. Chernikov * 15579f7d47b0SAlexander V. Chernikov */ 15589f7d47b0SAlexander V. Chernikov 155968394ec8SAlexander V. Chernikov struct ifidx { 156068394ec8SAlexander V. Chernikov uint16_t kidx; 156168394ec8SAlexander V. Chernikov uint16_t spare; 156268394ec8SAlexander V. Chernikov uint32_t value; 156368394ec8SAlexander V. Chernikov }; 156468394ec8SAlexander V. Chernikov 156568394ec8SAlexander V. Chernikov struct iftable_cfg; 156668394ec8SAlexander V. Chernikov 156768394ec8SAlexander V. Chernikov struct ifentry { 156868394ec8SAlexander V. Chernikov struct named_object no; 156968394ec8SAlexander V. Chernikov struct ipfw_ifc ic; 157068394ec8SAlexander V. Chernikov struct iftable_cfg *icfg; 157168394ec8SAlexander V. Chernikov uint32_t value; 157268394ec8SAlexander V. Chernikov int linked; 157368394ec8SAlexander V. Chernikov }; 157468394ec8SAlexander V. Chernikov 157568394ec8SAlexander V. Chernikov struct iftable_cfg { 157668394ec8SAlexander V. Chernikov struct namedobj_instance *ii; 157768394ec8SAlexander V. Chernikov struct ip_fw_chain *ch; 157868394ec8SAlexander V. Chernikov struct table_info *ti; 157968394ec8SAlexander V. Chernikov void *main_ptr; 158068394ec8SAlexander V. Chernikov size_t size; /* Number of items allocated in array */ 158168394ec8SAlexander V. Chernikov size_t count; /* Number of all items */ 158268394ec8SAlexander V. Chernikov size_t used; /* Number of items _active_ now */ 158368394ec8SAlexander V. Chernikov }; 158468394ec8SAlexander V. Chernikov 15850bce0c23SAlexander V. Chernikov struct ta_buf_ifidx 15860bce0c23SAlexander V. Chernikov { 15870bce0c23SAlexander V. Chernikov struct ifentry *ife; 15880bce0c23SAlexander V. Chernikov uint32_t value; 15890bce0c23SAlexander V. Chernikov }; 159068394ec8SAlexander V. Chernikov 159168394ec8SAlexander V. Chernikov int compare_ifidx(const void *k, const void *v); 159268394ec8SAlexander V. Chernikov static void if_notifier(struct ip_fw_chain *ch, void *cbdata, uint16_t ifindex); 159368394ec8SAlexander V. Chernikov 159468394ec8SAlexander V. Chernikov int 159568394ec8SAlexander V. Chernikov compare_ifidx(const void *k, const void *v) 159668394ec8SAlexander V. Chernikov { 159768394ec8SAlexander V. Chernikov struct ifidx *ifidx; 159868394ec8SAlexander V. Chernikov uint16_t key; 159968394ec8SAlexander V. Chernikov 160068394ec8SAlexander V. Chernikov key = *((uint16_t *)k); 160168394ec8SAlexander V. Chernikov ifidx = (struct ifidx *)v; 160268394ec8SAlexander V. Chernikov 160368394ec8SAlexander V. Chernikov if (key < ifidx->kidx) 160468394ec8SAlexander V. Chernikov return (-1); 160568394ec8SAlexander V. Chernikov else if (key > ifidx->kidx) 160668394ec8SAlexander V. Chernikov return (1); 160768394ec8SAlexander V. Chernikov 160868394ec8SAlexander V. Chernikov return (0); 160968394ec8SAlexander V. Chernikov } 161068394ec8SAlexander V. Chernikov 161168394ec8SAlexander V. Chernikov /* 161268394ec8SAlexander V. Chernikov * Adds item @item with key @key into ascending-sorted array @base. 161368394ec8SAlexander V. Chernikov * Assumes @base has enough additional storage. 161468394ec8SAlexander V. Chernikov * 161568394ec8SAlexander V. Chernikov * Returns 1 on success, 0 on duplicate key. 161668394ec8SAlexander V. Chernikov */ 16179f7d47b0SAlexander V. Chernikov static int 161868394ec8SAlexander V. Chernikov badd(const void *key, void *item, void *base, size_t nmemb, 161968394ec8SAlexander V. Chernikov size_t size, int (*compar) (const void *, const void *)) 162068394ec8SAlexander V. Chernikov { 162168394ec8SAlexander V. Chernikov int min, max, mid, shift, res; 162268394ec8SAlexander V. Chernikov caddr_t paddr; 162368394ec8SAlexander V. Chernikov 162468394ec8SAlexander V. Chernikov if (nmemb == 0) { 162568394ec8SAlexander V. Chernikov memcpy(base, item, size); 162668394ec8SAlexander V. Chernikov return (1); 162768394ec8SAlexander V. Chernikov } 162868394ec8SAlexander V. Chernikov 162968394ec8SAlexander V. Chernikov /* Binary search */ 163068394ec8SAlexander V. Chernikov min = 0; 163168394ec8SAlexander V. Chernikov max = nmemb - 1; 163268394ec8SAlexander V. Chernikov mid = 0; 163368394ec8SAlexander V. Chernikov while (min <= max) { 163468394ec8SAlexander V. Chernikov mid = (min + max) / 2; 163568394ec8SAlexander V. Chernikov res = compar(key, (const void *)((caddr_t)base + mid * size)); 163668394ec8SAlexander V. Chernikov if (res == 0) 163768394ec8SAlexander V. Chernikov return (0); 163868394ec8SAlexander V. Chernikov 163968394ec8SAlexander V. Chernikov if (res > 0) 164068394ec8SAlexander V. Chernikov min = mid + 1; 164168394ec8SAlexander V. Chernikov else 164268394ec8SAlexander V. Chernikov max = mid - 1; 164368394ec8SAlexander V. Chernikov } 164468394ec8SAlexander V. Chernikov 164568394ec8SAlexander V. Chernikov /* Item not found. */ 164668394ec8SAlexander V. Chernikov res = compar(key, (const void *)((caddr_t)base + mid * size)); 164768394ec8SAlexander V. Chernikov if (res > 0) 164868394ec8SAlexander V. Chernikov shift = mid + 1; 164968394ec8SAlexander V. Chernikov else 165068394ec8SAlexander V. Chernikov shift = mid; 165168394ec8SAlexander V. Chernikov 165268394ec8SAlexander V. Chernikov paddr = (caddr_t)base + shift * size; 165368394ec8SAlexander V. Chernikov if (nmemb > shift) 165468394ec8SAlexander V. Chernikov memmove(paddr + size, paddr, (nmemb - shift) * size); 165568394ec8SAlexander V. Chernikov 165668394ec8SAlexander V. Chernikov memcpy(paddr, item, size); 165768394ec8SAlexander V. Chernikov 165868394ec8SAlexander V. Chernikov return (1); 165968394ec8SAlexander V. Chernikov } 166068394ec8SAlexander V. Chernikov 166168394ec8SAlexander V. Chernikov /* 166268394ec8SAlexander V. Chernikov * Deletes item with key @key from ascending-sorted array @base. 166368394ec8SAlexander V. Chernikov * 166468394ec8SAlexander V. Chernikov * Returns 1 on success, 0 for non-existent key. 166568394ec8SAlexander V. Chernikov */ 166668394ec8SAlexander V. Chernikov static int 166768394ec8SAlexander V. Chernikov bdel(const void *key, void *base, size_t nmemb, size_t size, 166868394ec8SAlexander V. Chernikov int (*compar) (const void *, const void *)) 166968394ec8SAlexander V. Chernikov { 167068394ec8SAlexander V. Chernikov caddr_t item; 167168394ec8SAlexander V. Chernikov size_t sz; 167268394ec8SAlexander V. Chernikov 167368394ec8SAlexander V. Chernikov item = (caddr_t)bsearch(key, base, nmemb, size, compar); 167468394ec8SAlexander V. Chernikov 167568394ec8SAlexander V. Chernikov if (item == NULL) 167668394ec8SAlexander V. Chernikov return (0); 167768394ec8SAlexander V. Chernikov 167868394ec8SAlexander V. Chernikov sz = (caddr_t)base + nmemb * size - item; 167968394ec8SAlexander V. Chernikov 168068394ec8SAlexander V. Chernikov if (sz > 0) 168168394ec8SAlexander V. Chernikov memmove(item, item + size, sz); 168268394ec8SAlexander V. Chernikov 168368394ec8SAlexander V. Chernikov return (1); 168468394ec8SAlexander V. Chernikov } 168568394ec8SAlexander V. Chernikov 168668394ec8SAlexander V. Chernikov static struct ifidx * 168768394ec8SAlexander V. Chernikov ifidx_find(struct table_info *ti, void *key) 168868394ec8SAlexander V. Chernikov { 168968394ec8SAlexander V. Chernikov struct ifidx *ifi; 169068394ec8SAlexander V. Chernikov 169168394ec8SAlexander V. Chernikov ifi = bsearch(key, ti->state, ti->data, sizeof(struct ifidx), 169268394ec8SAlexander V. Chernikov compare_ifidx); 169368394ec8SAlexander V. Chernikov 169468394ec8SAlexander V. Chernikov return (ifi); 169568394ec8SAlexander V. Chernikov } 169668394ec8SAlexander V. Chernikov 169768394ec8SAlexander V. Chernikov static int 169868394ec8SAlexander V. Chernikov ta_lookup_ifidx(struct table_info *ti, void *key, uint32_t keylen, 16999f7d47b0SAlexander V. Chernikov uint32_t *val) 17009f7d47b0SAlexander V. Chernikov { 170168394ec8SAlexander V. Chernikov struct ifidx *ifi; 17029f7d47b0SAlexander V. Chernikov 170368394ec8SAlexander V. Chernikov ifi = ifidx_find(ti, key); 17049f7d47b0SAlexander V. Chernikov 170568394ec8SAlexander V. Chernikov if (ifi != NULL) { 170668394ec8SAlexander V. Chernikov *val = ifi->value; 17079f7d47b0SAlexander V. Chernikov return (1); 17089f7d47b0SAlexander V. Chernikov } 17099f7d47b0SAlexander V. Chernikov 17109f7d47b0SAlexander V. Chernikov return (0); 17119f7d47b0SAlexander V. Chernikov } 17129f7d47b0SAlexander V. Chernikov 17139f7d47b0SAlexander V. Chernikov static int 171468394ec8SAlexander V. Chernikov ta_init_ifidx(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti, 1715914bffb6SAlexander V. Chernikov char *data, uint8_t tflags) 17169f7d47b0SAlexander V. Chernikov { 171768394ec8SAlexander V. Chernikov struct iftable_cfg *icfg; 17189f7d47b0SAlexander V. Chernikov 171968394ec8SAlexander V. Chernikov icfg = malloc(sizeof(struct iftable_cfg), M_IPFW, M_WAITOK | M_ZERO); 17209f7d47b0SAlexander V. Chernikov 172168394ec8SAlexander V. Chernikov icfg->ii = ipfw_objhash_create(16); 17220bce0c23SAlexander V. Chernikov icfg->size = 16; 17230bce0c23SAlexander V. Chernikov icfg->main_ptr = malloc(sizeof(struct ifidx) * icfg->size, M_IPFW, 172468394ec8SAlexander V. Chernikov M_WAITOK | M_ZERO); 172568394ec8SAlexander V. Chernikov icfg->ch = ch; 17269f7d47b0SAlexander V. Chernikov 172768394ec8SAlexander V. Chernikov *ta_state = icfg; 172868394ec8SAlexander V. Chernikov ti->state = icfg->main_ptr; 172968394ec8SAlexander V. Chernikov ti->lookup = ta_lookup_ifidx; 17309f7d47b0SAlexander V. Chernikov 17319f7d47b0SAlexander V. Chernikov return (0); 17329f7d47b0SAlexander V. Chernikov } 17339f7d47b0SAlexander V. Chernikov 173468394ec8SAlexander V. Chernikov /* 173568394ec8SAlexander V. Chernikov * Handle tableinfo @ti pointer change (on table array resize). 173668394ec8SAlexander V. Chernikov */ 173768394ec8SAlexander V. Chernikov static void 173868394ec8SAlexander V. Chernikov ta_change_ti_ifidx(void *ta_state, struct table_info *ti) 173968394ec8SAlexander V. Chernikov { 174068394ec8SAlexander V. Chernikov struct iftable_cfg *icfg; 174168394ec8SAlexander V. Chernikov 174268394ec8SAlexander V. Chernikov icfg = (struct iftable_cfg *)ta_state; 174368394ec8SAlexander V. Chernikov icfg->ti = ti; 174468394ec8SAlexander V. Chernikov } 17459f7d47b0SAlexander V. Chernikov 17469f7d47b0SAlexander V. Chernikov static void 174768394ec8SAlexander V. Chernikov destroy_ifidx_locked(struct namedobj_instance *ii, struct named_object *no, 174868394ec8SAlexander V. Chernikov void *arg) 17499f7d47b0SAlexander V. Chernikov { 175068394ec8SAlexander V. Chernikov struct ifentry *ife; 175168394ec8SAlexander V. Chernikov struct ip_fw_chain *ch; 17529f7d47b0SAlexander V. Chernikov 175368394ec8SAlexander V. Chernikov ch = (struct ip_fw_chain *)arg; 175468394ec8SAlexander V. Chernikov ife = (struct ifentry *)no; 175568394ec8SAlexander V. Chernikov 175668394ec8SAlexander V. Chernikov ipfw_iface_del_notify(ch, &ife->ic); 175768394ec8SAlexander V. Chernikov free(ife, M_IPFW_TBL); 17589f7d47b0SAlexander V. Chernikov } 17599f7d47b0SAlexander V. Chernikov 176068394ec8SAlexander V. Chernikov 176168394ec8SAlexander V. Chernikov /* 176268394ec8SAlexander V. Chernikov * Destroys table @ti 176368394ec8SAlexander V. Chernikov */ 176468394ec8SAlexander V. Chernikov static void 176568394ec8SAlexander V. Chernikov ta_destroy_ifidx(void *ta_state, struct table_info *ti) 17669f7d47b0SAlexander V. Chernikov { 176768394ec8SAlexander V. Chernikov struct iftable_cfg *icfg; 176868394ec8SAlexander V. Chernikov struct ip_fw_chain *ch; 176968394ec8SAlexander V. Chernikov 177068394ec8SAlexander V. Chernikov icfg = (struct iftable_cfg *)ta_state; 177168394ec8SAlexander V. Chernikov ch = icfg->ch; 177268394ec8SAlexander V. Chernikov 177368394ec8SAlexander V. Chernikov if (icfg->main_ptr != NULL) 177468394ec8SAlexander V. Chernikov free(icfg->main_ptr, M_IPFW); 177568394ec8SAlexander V. Chernikov 177668394ec8SAlexander V. Chernikov ipfw_objhash_foreach(icfg->ii, destroy_ifidx_locked, ch); 177768394ec8SAlexander V. Chernikov 177868394ec8SAlexander V. Chernikov ipfw_objhash_destroy(icfg->ii); 177968394ec8SAlexander V. Chernikov 178068394ec8SAlexander V. Chernikov free(icfg, M_IPFW); 178168394ec8SAlexander V. Chernikov } 178268394ec8SAlexander V. Chernikov 178368394ec8SAlexander V. Chernikov /* 17845f379342SAlexander V. Chernikov * Provide algo-specific table info 17855f379342SAlexander V. Chernikov */ 17865f379342SAlexander V. Chernikov static void 17875f379342SAlexander V. Chernikov ta_dump_ifidx_tinfo(void *ta_state, struct table_info *ti, ipfw_ta_tinfo *tinfo) 17885f379342SAlexander V. Chernikov { 17895f379342SAlexander V. Chernikov struct iftable_cfg *cfg; 17905f379342SAlexander V. Chernikov 17915f379342SAlexander V. Chernikov cfg = (struct iftable_cfg *)ta_state; 17925f379342SAlexander V. Chernikov 17935f379342SAlexander V. Chernikov tinfo->taclass4 = IPFW_TACLASS_ARRAY; 17945f379342SAlexander V. Chernikov tinfo->size4 = cfg->size; 17955f379342SAlexander V. Chernikov tinfo->count4 = cfg->used; 17965f379342SAlexander V. Chernikov tinfo->itemsize4 = sizeof(struct ifidx); 17975f379342SAlexander V. Chernikov } 17985f379342SAlexander V. Chernikov 17995f379342SAlexander V. Chernikov /* 180068394ec8SAlexander V. Chernikov * Prepare state to add to the table: 180168394ec8SAlexander V. Chernikov * allocate ifentry and reference needed interface. 180268394ec8SAlexander V. Chernikov */ 18039f7d47b0SAlexander V. Chernikov static int 180468394ec8SAlexander V. Chernikov ta_prepare_add_ifidx(struct ip_fw_chain *ch, struct tentry_info *tei, 180568394ec8SAlexander V. Chernikov void *ta_buf) 180668394ec8SAlexander V. Chernikov { 180768394ec8SAlexander V. Chernikov struct ta_buf_ifidx *tb; 180868394ec8SAlexander V. Chernikov char *ifname; 180968394ec8SAlexander V. Chernikov struct ifentry *ife; 181068394ec8SAlexander V. Chernikov 181168394ec8SAlexander V. Chernikov tb = (struct ta_buf_ifidx *)ta_buf; 181268394ec8SAlexander V. Chernikov 181368394ec8SAlexander V. Chernikov /* Check if string is terminated */ 181468394ec8SAlexander V. Chernikov ifname = (char *)tei->paddr; 181568394ec8SAlexander V. Chernikov if (strnlen(ifname, IF_NAMESIZE) == IF_NAMESIZE) 181668394ec8SAlexander V. Chernikov return (EINVAL); 181768394ec8SAlexander V. Chernikov 181868394ec8SAlexander V. Chernikov ife = malloc(sizeof(struct ifentry), M_IPFW_TBL, M_WAITOK | M_ZERO); 181968394ec8SAlexander V. Chernikov ife->value = tei->value; 182068394ec8SAlexander V. Chernikov ife->ic.cb = if_notifier; 182168394ec8SAlexander V. Chernikov ife->ic.cbdata = ife; 182268394ec8SAlexander V. Chernikov 182368394ec8SAlexander V. Chernikov if (ipfw_iface_ref(ch, ifname, &ife->ic) != 0) 182468394ec8SAlexander V. Chernikov return (EINVAL); 182568394ec8SAlexander V. Chernikov 182668394ec8SAlexander V. Chernikov /* Use ipfw_iface 'ifname' field as stable storage */ 182768394ec8SAlexander V. Chernikov ife->no.name = ife->ic.iface->ifname; 182868394ec8SAlexander V. Chernikov 182968394ec8SAlexander V. Chernikov tb->ife = ife; 183068394ec8SAlexander V. Chernikov 183168394ec8SAlexander V. Chernikov return (0); 183268394ec8SAlexander V. Chernikov } 183368394ec8SAlexander V. Chernikov 183468394ec8SAlexander V. Chernikov static int 1835adea6201SAlexander V. Chernikov ta_add_ifidx(void *ta_state, struct table_info *ti, struct tentry_info *tei, 1836b6ee846eSAlexander V. Chernikov void *ta_buf, uint32_t *pnum) 183768394ec8SAlexander V. Chernikov { 183868394ec8SAlexander V. Chernikov struct iftable_cfg *icfg; 183968394ec8SAlexander V. Chernikov struct ifentry *ife, *tmp; 184068394ec8SAlexander V. Chernikov struct ta_buf_ifidx *tb; 184168394ec8SAlexander V. Chernikov struct ipfw_iface *iif; 184268394ec8SAlexander V. Chernikov struct ifidx *ifi; 184368394ec8SAlexander V. Chernikov char *ifname; 1844648e8380SAlexander V. Chernikov uint32_t value; 184568394ec8SAlexander V. Chernikov 184668394ec8SAlexander V. Chernikov tb = (struct ta_buf_ifidx *)ta_buf; 184768394ec8SAlexander V. Chernikov ifname = (char *)tei->paddr; 184868394ec8SAlexander V. Chernikov icfg = (struct iftable_cfg *)ta_state; 184968394ec8SAlexander V. Chernikov ife = tb->ife; 185068394ec8SAlexander V. Chernikov 185168394ec8SAlexander V. Chernikov ife->icfg = icfg; 185268394ec8SAlexander V. Chernikov 185368394ec8SAlexander V. Chernikov tmp = (struct ifentry *)ipfw_objhash_lookup_name(icfg->ii, 0, ifname); 185468394ec8SAlexander V. Chernikov 185568394ec8SAlexander V. Chernikov if (tmp != NULL) { 185668394ec8SAlexander V. Chernikov if ((tei->flags & TEI_FLAGS_UPDATE) == 0) 185768394ec8SAlexander V. Chernikov return (EEXIST); 185868394ec8SAlexander V. Chernikov 1859648e8380SAlexander V. Chernikov /* Exchange values in @tmp and @tei */ 1860648e8380SAlexander V. Chernikov value = tmp->value; 1861648e8380SAlexander V. Chernikov tmp->value = tei->value; 1862648e8380SAlexander V. Chernikov tei->value = value; 186368394ec8SAlexander V. Chernikov 1864648e8380SAlexander V. Chernikov iif = tmp->ic.iface; 186568394ec8SAlexander V. Chernikov if (iif->resolved != 0) { 1866648e8380SAlexander V. Chernikov /* We have to update runtime value, too */ 186768394ec8SAlexander V. Chernikov ifi = ifidx_find(ti, &iif->ifindex); 186868394ec8SAlexander V. Chernikov ifi->value = ife->value; 186968394ec8SAlexander V. Chernikov } 187068394ec8SAlexander V. Chernikov 187168394ec8SAlexander V. Chernikov /* Indicate that update has happened instead of addition */ 187268394ec8SAlexander V. Chernikov tei->flags |= TEI_FLAGS_UPDATED; 1873adea6201SAlexander V. Chernikov *pnum = 0; 187468394ec8SAlexander V. Chernikov return (0); 187568394ec8SAlexander V. Chernikov } 187668394ec8SAlexander V. Chernikov 18774c0c07a5SAlexander V. Chernikov if ((tei->flags & TEI_FLAGS_DONTADD) != 0) 18784c0c07a5SAlexander V. Chernikov return (EFBIG); 18794c0c07a5SAlexander V. Chernikov 188068394ec8SAlexander V. Chernikov /* Link to internal list */ 188168394ec8SAlexander V. Chernikov ipfw_objhash_add(icfg->ii, &ife->no); 188268394ec8SAlexander V. Chernikov 188368394ec8SAlexander V. Chernikov /* Link notifier (possible running its callback) */ 188468394ec8SAlexander V. Chernikov ipfw_iface_add_notify(icfg->ch, &ife->ic); 188568394ec8SAlexander V. Chernikov icfg->count++; 188668394ec8SAlexander V. Chernikov 188768394ec8SAlexander V. Chernikov tb->ife = NULL; 1888adea6201SAlexander V. Chernikov *pnum = 1; 188968394ec8SAlexander V. Chernikov 189068394ec8SAlexander V. Chernikov return (0); 189168394ec8SAlexander V. Chernikov } 189268394ec8SAlexander V. Chernikov 189368394ec8SAlexander V. Chernikov /* 189468394ec8SAlexander V. Chernikov * Prepare to delete key from table. 189568394ec8SAlexander V. Chernikov * Do basic interface name checks. 189668394ec8SAlexander V. Chernikov */ 189768394ec8SAlexander V. Chernikov static int 189868394ec8SAlexander V. Chernikov ta_prepare_del_ifidx(struct ip_fw_chain *ch, struct tentry_info *tei, 189968394ec8SAlexander V. Chernikov void *ta_buf) 19009f7d47b0SAlexander V. Chernikov { 190174b941f0SAlexander V. Chernikov struct ta_buf_ifidx *tb; 1902e0a8b9eeSAlexander V. Chernikov char *ifname; 19039f7d47b0SAlexander V. Chernikov 190474b941f0SAlexander V. Chernikov tb = (struct ta_buf_ifidx *)ta_buf; 19059f7d47b0SAlexander V. Chernikov 19069f7d47b0SAlexander V. Chernikov /* Check if string is terminated */ 1907e0a8b9eeSAlexander V. Chernikov ifname = (char *)tei->paddr; 1908e0a8b9eeSAlexander V. Chernikov if (strnlen(ifname, IF_NAMESIZE) == IF_NAMESIZE) 19099f7d47b0SAlexander V. Chernikov return (EINVAL); 19109f7d47b0SAlexander V. Chernikov 19119f7d47b0SAlexander V. Chernikov return (0); 19129f7d47b0SAlexander V. Chernikov } 19139f7d47b0SAlexander V. Chernikov 191468394ec8SAlexander V. Chernikov /* 191568394ec8SAlexander V. Chernikov * Remove key from both configuration list and 191668394ec8SAlexander V. Chernikov * runtime array. Removed interface notification. 191768394ec8SAlexander V. Chernikov */ 19189f7d47b0SAlexander V. Chernikov static int 1919adea6201SAlexander V. Chernikov ta_del_ifidx(void *ta_state, struct table_info *ti, struct tentry_info *tei, 1920b6ee846eSAlexander V. Chernikov void *ta_buf, uint32_t *pnum) 19219f7d47b0SAlexander V. Chernikov { 192268394ec8SAlexander V. Chernikov struct iftable_cfg *icfg; 192368394ec8SAlexander V. Chernikov struct ifentry *ife; 192468394ec8SAlexander V. Chernikov struct ta_buf_ifidx *tb; 192568394ec8SAlexander V. Chernikov char *ifname; 192668394ec8SAlexander V. Chernikov uint16_t ifindex; 192768394ec8SAlexander V. Chernikov int res; 19289f7d47b0SAlexander V. Chernikov 192968394ec8SAlexander V. Chernikov tb = (struct ta_buf_ifidx *)ta_buf; 193068394ec8SAlexander V. Chernikov ifname = (char *)tei->paddr; 193168394ec8SAlexander V. Chernikov icfg = (struct iftable_cfg *)ta_state; 193268394ec8SAlexander V. Chernikov ife = tb->ife; 19339f7d47b0SAlexander V. Chernikov 193468394ec8SAlexander V. Chernikov ife = (struct ifentry *)ipfw_objhash_lookup_name(icfg->ii, 0, ifname); 19359f7d47b0SAlexander V. Chernikov 193668394ec8SAlexander V. Chernikov if (ife == NULL) 193781d3153dSAlexander V. Chernikov return (ENOENT); 19389f7d47b0SAlexander V. Chernikov 193968394ec8SAlexander V. Chernikov if (ife->linked != 0) { 194068394ec8SAlexander V. Chernikov /* We have to remove item from runtime */ 194168394ec8SAlexander V. Chernikov ifindex = ife->ic.iface->ifindex; 194268394ec8SAlexander V. Chernikov 194368394ec8SAlexander V. Chernikov res = bdel(&ifindex, icfg->main_ptr, icfg->used, 194468394ec8SAlexander V. Chernikov sizeof(struct ifidx), compare_ifidx); 194568394ec8SAlexander V. Chernikov 194668394ec8SAlexander V. Chernikov KASSERT(res == 1, ("index %d does not exist", ifindex)); 194768394ec8SAlexander V. Chernikov icfg->used--; 194868394ec8SAlexander V. Chernikov ti->data = icfg->used; 194968394ec8SAlexander V. Chernikov ife->linked = 0; 195068394ec8SAlexander V. Chernikov } 195168394ec8SAlexander V. Chernikov 195268394ec8SAlexander V. Chernikov /* Unlink from local list */ 195368394ec8SAlexander V. Chernikov ipfw_objhash_del(icfg->ii, &ife->no); 195468394ec8SAlexander V. Chernikov /* Unlink notifier */ 195568394ec8SAlexander V. Chernikov ipfw_iface_del_notify(icfg->ch, &ife->ic); 195668394ec8SAlexander V. Chernikov 195768394ec8SAlexander V. Chernikov icfg->count--; 1958648e8380SAlexander V. Chernikov tei->value = ife->value; 195968394ec8SAlexander V. Chernikov 196068394ec8SAlexander V. Chernikov tb->ife = ife; 1961adea6201SAlexander V. Chernikov *pnum = 1; 196268394ec8SAlexander V. Chernikov 19639f7d47b0SAlexander V. Chernikov return (0); 19649f7d47b0SAlexander V. Chernikov } 19659f7d47b0SAlexander V. Chernikov 196668394ec8SAlexander V. Chernikov /* 196768394ec8SAlexander V. Chernikov * Flush deleted entry. 196868394ec8SAlexander V. Chernikov * Drops interface reference and frees entry. 196968394ec8SAlexander V. Chernikov */ 19709f7d47b0SAlexander V. Chernikov static void 197168394ec8SAlexander V. Chernikov ta_flush_ifidx_entry(struct ip_fw_chain *ch, struct tentry_info *tei, 197268394ec8SAlexander V. Chernikov void *ta_buf) 19739f7d47b0SAlexander V. Chernikov { 197468394ec8SAlexander V. Chernikov struct ta_buf_ifidx *tb; 19759f7d47b0SAlexander V. Chernikov 197668394ec8SAlexander V. Chernikov tb = (struct ta_buf_ifidx *)ta_buf; 19779f7d47b0SAlexander V. Chernikov 197868394ec8SAlexander V. Chernikov if (tb->ife != NULL) { 197968394ec8SAlexander V. Chernikov /* Unlink first */ 198068394ec8SAlexander V. Chernikov ipfw_iface_unref(ch, &tb->ife->ic); 198168394ec8SAlexander V. Chernikov free(tb->ife, M_IPFW_TBL); 198268394ec8SAlexander V. Chernikov } 198368394ec8SAlexander V. Chernikov } 198468394ec8SAlexander V. Chernikov 198568394ec8SAlexander V. Chernikov 198668394ec8SAlexander V. Chernikov /* 198768394ec8SAlexander V. Chernikov * Handle interface announce/withdrawal for particular table. 198868394ec8SAlexander V. Chernikov * Every real runtime array modification happens here. 198968394ec8SAlexander V. Chernikov */ 199068394ec8SAlexander V. Chernikov static void 199168394ec8SAlexander V. Chernikov if_notifier(struct ip_fw_chain *ch, void *cbdata, uint16_t ifindex) 199268394ec8SAlexander V. Chernikov { 199368394ec8SAlexander V. Chernikov struct ifentry *ife; 199468394ec8SAlexander V. Chernikov struct ifidx ifi; 199568394ec8SAlexander V. Chernikov struct iftable_cfg *icfg; 199668394ec8SAlexander V. Chernikov struct table_info *ti; 199768394ec8SAlexander V. Chernikov int res; 199868394ec8SAlexander V. Chernikov 199968394ec8SAlexander V. Chernikov ife = (struct ifentry *)cbdata; 200068394ec8SAlexander V. Chernikov icfg = ife->icfg; 200168394ec8SAlexander V. Chernikov ti = icfg->ti; 200268394ec8SAlexander V. Chernikov 200368394ec8SAlexander V. Chernikov KASSERT(ti != NULL, ("ti=NULL, check change_ti handler")); 200468394ec8SAlexander V. Chernikov 200568394ec8SAlexander V. Chernikov if (ife->linked == 0 && ifindex != 0) { 200668394ec8SAlexander V. Chernikov /* Interface announce */ 200768394ec8SAlexander V. Chernikov ifi.kidx = ifindex; 200868394ec8SAlexander V. Chernikov ifi.spare = 0; 200968394ec8SAlexander V. Chernikov ifi.value = ife->value; 201068394ec8SAlexander V. Chernikov res = badd(&ifindex, &ifi, icfg->main_ptr, icfg->used, 201168394ec8SAlexander V. Chernikov sizeof(struct ifidx), compare_ifidx); 201268394ec8SAlexander V. Chernikov KASSERT(res == 1, ("index %d already exists", ifindex)); 201368394ec8SAlexander V. Chernikov icfg->used++; 201468394ec8SAlexander V. Chernikov ti->data = icfg->used; 201568394ec8SAlexander V. Chernikov ife->linked = 1; 201668394ec8SAlexander V. Chernikov } else if (ife->linked != 0 && ifindex == 0) { 201768394ec8SAlexander V. Chernikov /* Interface withdrawal */ 201868394ec8SAlexander V. Chernikov ifindex = ife->ic.iface->ifindex; 201968394ec8SAlexander V. Chernikov 202068394ec8SAlexander V. Chernikov res = bdel(&ifindex, icfg->main_ptr, icfg->used, 202168394ec8SAlexander V. Chernikov sizeof(struct ifidx), compare_ifidx); 202268394ec8SAlexander V. Chernikov 202368394ec8SAlexander V. Chernikov KASSERT(res == 1, ("index %d does not exist", ifindex)); 202468394ec8SAlexander V. Chernikov icfg->used--; 202568394ec8SAlexander V. Chernikov ti->data = icfg->used; 202668394ec8SAlexander V. Chernikov ife->linked = 0; 202768394ec8SAlexander V. Chernikov } 202868394ec8SAlexander V. Chernikov } 202968394ec8SAlexander V. Chernikov 203068394ec8SAlexander V. Chernikov 203168394ec8SAlexander V. Chernikov /* 203268394ec8SAlexander V. Chernikov * Table growing callbacks. 203368394ec8SAlexander V. Chernikov */ 203468394ec8SAlexander V. Chernikov 2035b6ee846eSAlexander V. Chernikov static int 2036b6ee846eSAlexander V. Chernikov ta_has_space_ifidx(void *ta_state, struct table_info *ti, uint32_t count, 2037b6ee846eSAlexander V. Chernikov uint64_t *pflags) 2038b6ee846eSAlexander V. Chernikov { 2039b6ee846eSAlexander V. Chernikov struct iftable_cfg *cfg; 20400bce0c23SAlexander V. Chernikov uint32_t size; 2041b6ee846eSAlexander V. Chernikov 2042b6ee846eSAlexander V. Chernikov cfg = (struct iftable_cfg *)ta_state; 2043b6ee846eSAlexander V. Chernikov 20440bce0c23SAlexander V. Chernikov size = cfg->size; 20450bce0c23SAlexander V. Chernikov while (size < cfg->count + count) 20460bce0c23SAlexander V. Chernikov size *= 2; 20470bce0c23SAlexander V. Chernikov 20480bce0c23SAlexander V. Chernikov if (size != cfg->size) { 20490bce0c23SAlexander V. Chernikov *pflags = size; 2050b6ee846eSAlexander V. Chernikov return (0); 2051b6ee846eSAlexander V. Chernikov } 2052b6ee846eSAlexander V. Chernikov 2053b6ee846eSAlexander V. Chernikov return (1); 2054b6ee846eSAlexander V. Chernikov } 2055b6ee846eSAlexander V. Chernikov 205668394ec8SAlexander V. Chernikov /* 205768394ec8SAlexander V. Chernikov * Allocate ned, larger runtime ifidx array. 205868394ec8SAlexander V. Chernikov */ 205968394ec8SAlexander V. Chernikov static int 206068394ec8SAlexander V. Chernikov ta_prepare_mod_ifidx(void *ta_buf, uint64_t *pflags) 206168394ec8SAlexander V. Chernikov { 20620bce0c23SAlexander V. Chernikov struct mod_item *mi; 206368394ec8SAlexander V. Chernikov 20640bce0c23SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 206568394ec8SAlexander V. Chernikov 20660bce0c23SAlexander V. Chernikov memset(mi, 0, sizeof(struct mod_item)); 206768394ec8SAlexander V. Chernikov mi->size = *pflags; 206868394ec8SAlexander V. Chernikov mi->main_ptr = malloc(sizeof(struct ifidx) * mi->size, M_IPFW, 206968394ec8SAlexander V. Chernikov M_WAITOK | M_ZERO); 207068394ec8SAlexander V. Chernikov 207168394ec8SAlexander V. Chernikov return (0); 207268394ec8SAlexander V. Chernikov } 207368394ec8SAlexander V. Chernikov 207468394ec8SAlexander V. Chernikov /* 207568394ec8SAlexander V. Chernikov * Copy data from old runtime array to new one. 207668394ec8SAlexander V. Chernikov */ 207768394ec8SAlexander V. Chernikov static int 207868394ec8SAlexander V. Chernikov ta_fill_mod_ifidx(void *ta_state, struct table_info *ti, void *ta_buf, 207968394ec8SAlexander V. Chernikov uint64_t *pflags) 208068394ec8SAlexander V. Chernikov { 20810bce0c23SAlexander V. Chernikov struct mod_item *mi; 208268394ec8SAlexander V. Chernikov struct iftable_cfg *icfg; 208368394ec8SAlexander V. Chernikov 20840bce0c23SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 208568394ec8SAlexander V. Chernikov icfg = (struct iftable_cfg *)ta_state; 208668394ec8SAlexander V. Chernikov 208768394ec8SAlexander V. Chernikov /* Check if we still need to grow array */ 208868394ec8SAlexander V. Chernikov if (icfg->size >= mi->size) { 208968394ec8SAlexander V. Chernikov *pflags = 0; 209068394ec8SAlexander V. Chernikov return (0); 209168394ec8SAlexander V. Chernikov } 209268394ec8SAlexander V. Chernikov 209368394ec8SAlexander V. Chernikov memcpy(mi->main_ptr, icfg->main_ptr, icfg->used * sizeof(struct ifidx)); 209468394ec8SAlexander V. Chernikov 209568394ec8SAlexander V. Chernikov return (0); 209668394ec8SAlexander V. Chernikov } 209768394ec8SAlexander V. Chernikov 209868394ec8SAlexander V. Chernikov /* 209968394ec8SAlexander V. Chernikov * Switch old & new arrays. 210068394ec8SAlexander V. Chernikov */ 210168394ec8SAlexander V. Chernikov static int 210268394ec8SAlexander V. Chernikov ta_modify_ifidx(void *ta_state, struct table_info *ti, void *ta_buf, 210368394ec8SAlexander V. Chernikov uint64_t pflags) 210468394ec8SAlexander V. Chernikov { 21050bce0c23SAlexander V. Chernikov struct mod_item *mi; 210668394ec8SAlexander V. Chernikov struct iftable_cfg *icfg; 210768394ec8SAlexander V. Chernikov void *old_ptr; 210868394ec8SAlexander V. Chernikov 21090bce0c23SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 211068394ec8SAlexander V. Chernikov icfg = (struct iftable_cfg *)ta_state; 211168394ec8SAlexander V. Chernikov 211268394ec8SAlexander V. Chernikov old_ptr = icfg->main_ptr; 211368394ec8SAlexander V. Chernikov icfg->main_ptr = mi->main_ptr; 211468394ec8SAlexander V. Chernikov icfg->size = mi->size; 211568394ec8SAlexander V. Chernikov ti->state = icfg->main_ptr; 211668394ec8SAlexander V. Chernikov 211768394ec8SAlexander V. Chernikov mi->main_ptr = old_ptr; 211868394ec8SAlexander V. Chernikov 211968394ec8SAlexander V. Chernikov return (0); 212068394ec8SAlexander V. Chernikov } 212168394ec8SAlexander V. Chernikov 212268394ec8SAlexander V. Chernikov /* 212368394ec8SAlexander V. Chernikov * Free unneded array. 212468394ec8SAlexander V. Chernikov */ 212568394ec8SAlexander V. Chernikov static void 212668394ec8SAlexander V. Chernikov ta_flush_mod_ifidx(void *ta_buf) 212768394ec8SAlexander V. Chernikov { 21280bce0c23SAlexander V. Chernikov struct mod_item *mi; 212968394ec8SAlexander V. Chernikov 21300bce0c23SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 213168394ec8SAlexander V. Chernikov if (mi->main_ptr != NULL) 213268394ec8SAlexander V. Chernikov free(mi->main_ptr, M_IPFW); 21339f7d47b0SAlexander V. Chernikov } 21349f7d47b0SAlexander V. Chernikov 21359f7d47b0SAlexander V. Chernikov static int 213668394ec8SAlexander V. Chernikov ta_dump_ifidx_tentry(void *ta_state, struct table_info *ti, void *e, 213781d3153dSAlexander V. Chernikov ipfw_obj_tentry *tent) 21389f7d47b0SAlexander V. Chernikov { 213968394ec8SAlexander V. Chernikov struct ifentry *ife; 21409f7d47b0SAlexander V. Chernikov 214168394ec8SAlexander V. Chernikov ife = (struct ifentry *)e; 214268394ec8SAlexander V. Chernikov 214381d3153dSAlexander V. Chernikov tent->masklen = 8 * IF_NAMESIZE; 214468394ec8SAlexander V. Chernikov memcpy(&tent->k, ife->no.name, IF_NAMESIZE); 214568394ec8SAlexander V. Chernikov tent->value = ife->value; 21469f7d47b0SAlexander V. Chernikov 21479f7d47b0SAlexander V. Chernikov return (0); 21489f7d47b0SAlexander V. Chernikov } 21499f7d47b0SAlexander V. Chernikov 215081d3153dSAlexander V. Chernikov static int 2151914bffb6SAlexander V. Chernikov ta_find_ifidx_tentry(void *ta_state, struct table_info *ti, 2152914bffb6SAlexander V. Chernikov ipfw_obj_tentry *tent) 215381d3153dSAlexander V. Chernikov { 215468394ec8SAlexander V. Chernikov struct iftable_cfg *icfg; 215568394ec8SAlexander V. Chernikov struct ifentry *ife; 215668394ec8SAlexander V. Chernikov char *ifname; 215781d3153dSAlexander V. Chernikov 215868394ec8SAlexander V. Chernikov icfg = (struct iftable_cfg *)ta_state; 2159914bffb6SAlexander V. Chernikov ifname = tent->k.iface; 216081d3153dSAlexander V. Chernikov 216168394ec8SAlexander V. Chernikov if (strnlen(ifname, IF_NAMESIZE) == IF_NAMESIZE) 216268394ec8SAlexander V. Chernikov return (EINVAL); 216381d3153dSAlexander V. Chernikov 216468394ec8SAlexander V. Chernikov ife = (struct ifentry *)ipfw_objhash_lookup_name(icfg->ii, 0, ifname); 216568394ec8SAlexander V. Chernikov 216668394ec8SAlexander V. Chernikov if (ife != NULL) { 216768394ec8SAlexander V. Chernikov ta_dump_ifidx_tentry(ta_state, ti, ife, tent); 216881d3153dSAlexander V. Chernikov return (0); 216981d3153dSAlexander V. Chernikov } 217081d3153dSAlexander V. Chernikov 217181d3153dSAlexander V. Chernikov return (ENOENT); 217281d3153dSAlexander V. Chernikov } 217381d3153dSAlexander V. Chernikov 217468394ec8SAlexander V. Chernikov struct wa_ifidx { 217568394ec8SAlexander V. Chernikov ta_foreach_f *f; 217668394ec8SAlexander V. Chernikov void *arg; 217768394ec8SAlexander V. Chernikov }; 217868394ec8SAlexander V. Chernikov 21799f7d47b0SAlexander V. Chernikov static void 218068394ec8SAlexander V. Chernikov foreach_ifidx(struct namedobj_instance *ii, struct named_object *no, 21819f7d47b0SAlexander V. Chernikov void *arg) 21829f7d47b0SAlexander V. Chernikov { 218368394ec8SAlexander V. Chernikov struct ifentry *ife; 218468394ec8SAlexander V. Chernikov struct wa_ifidx *wa; 21859f7d47b0SAlexander V. Chernikov 218668394ec8SAlexander V. Chernikov ife = (struct ifentry *)no; 218768394ec8SAlexander V. Chernikov wa = (struct wa_ifidx *)arg; 218868394ec8SAlexander V. Chernikov 218968394ec8SAlexander V. Chernikov wa->f(ife, wa->arg); 21909f7d47b0SAlexander V. Chernikov } 21919f7d47b0SAlexander V. Chernikov 219268394ec8SAlexander V. Chernikov static void 219368394ec8SAlexander V. Chernikov ta_foreach_ifidx(void *ta_state, struct table_info *ti, ta_foreach_f *f, 219468394ec8SAlexander V. Chernikov void *arg) 219568394ec8SAlexander V. Chernikov { 219668394ec8SAlexander V. Chernikov struct iftable_cfg *icfg; 219768394ec8SAlexander V. Chernikov struct wa_ifidx wa; 219868394ec8SAlexander V. Chernikov 219968394ec8SAlexander V. Chernikov icfg = (struct iftable_cfg *)ta_state; 220068394ec8SAlexander V. Chernikov 220168394ec8SAlexander V. Chernikov wa.f = f; 220268394ec8SAlexander V. Chernikov wa.arg = arg; 220368394ec8SAlexander V. Chernikov 220468394ec8SAlexander V. Chernikov ipfw_objhash_foreach(icfg->ii, foreach_ifidx, &wa); 220568394ec8SAlexander V. Chernikov } 220668394ec8SAlexander V. Chernikov 220774b941f0SAlexander V. Chernikov struct table_algo iface_idx = { 2208adea6201SAlexander V. Chernikov .name = "iface:array", 22099d099b4fSAlexander V. Chernikov .type = IPFW_TABLE_INTERFACE, 221057a1cf95SAlexander V. Chernikov .flags = TA_FLAG_DEFAULT, 221157a1cf95SAlexander V. Chernikov .ta_buf_size = sizeof(struct ta_buf_ifidx), 221268394ec8SAlexander V. Chernikov .init = ta_init_ifidx, 221368394ec8SAlexander V. Chernikov .destroy = ta_destroy_ifidx, 221468394ec8SAlexander V. Chernikov .prepare_add = ta_prepare_add_ifidx, 221568394ec8SAlexander V. Chernikov .prepare_del = ta_prepare_del_ifidx, 221668394ec8SAlexander V. Chernikov .add = ta_add_ifidx, 221768394ec8SAlexander V. Chernikov .del = ta_del_ifidx, 221868394ec8SAlexander V. Chernikov .flush_entry = ta_flush_ifidx_entry, 221968394ec8SAlexander V. Chernikov .foreach = ta_foreach_ifidx, 222068394ec8SAlexander V. Chernikov .dump_tentry = ta_dump_ifidx_tentry, 222168394ec8SAlexander V. Chernikov .find_tentry = ta_find_ifidx_tentry, 22225f379342SAlexander V. Chernikov .dump_tinfo = ta_dump_ifidx_tinfo, 2223b6ee846eSAlexander V. Chernikov .has_space = ta_has_space_ifidx, 222468394ec8SAlexander V. Chernikov .prepare_mod = ta_prepare_mod_ifidx, 222568394ec8SAlexander V. Chernikov .fill_mod = ta_fill_mod_ifidx, 222668394ec8SAlexander V. Chernikov .modify = ta_modify_ifidx, 222768394ec8SAlexander V. Chernikov .flush_mod = ta_flush_mod_ifidx, 222868394ec8SAlexander V. Chernikov .change_ti = ta_change_ti_ifidx, 22299f7d47b0SAlexander V. Chernikov }; 22309f7d47b0SAlexander V. Chernikov 2231b23d5de9SAlexander V. Chernikov /* 2232b23d5de9SAlexander V. Chernikov * Number array cmds. 2233b23d5de9SAlexander V. Chernikov * 2234b23d5de9SAlexander V. Chernikov * Implementation: 2235b23d5de9SAlexander V. Chernikov * 2236b23d5de9SAlexander V. Chernikov * Runtime part: 2237b23d5de9SAlexander V. Chernikov * - sorted array of "struct numarray" pointed by ti->state. 2238b23d5de9SAlexander V. Chernikov * Array is allocated with rounding up to NUMARRAY_CHUNK. 2239b23d5de9SAlexander V. Chernikov * - current array size is stored in ti->data 2240b23d5de9SAlexander V. Chernikov * 2241b23d5de9SAlexander V. Chernikov */ 2242b23d5de9SAlexander V. Chernikov 2243b23d5de9SAlexander V. Chernikov struct numarray { 2244b23d5de9SAlexander V. Chernikov uint32_t number; 2245b23d5de9SAlexander V. Chernikov uint32_t value; 2246b23d5de9SAlexander V. Chernikov }; 2247b23d5de9SAlexander V. Chernikov 2248b23d5de9SAlexander V. Chernikov struct numarray_cfg { 2249b23d5de9SAlexander V. Chernikov void *main_ptr; 2250b23d5de9SAlexander V. Chernikov size_t size; /* Number of items allocated in array */ 2251b23d5de9SAlexander V. Chernikov size_t used; /* Number of items _active_ now */ 2252b23d5de9SAlexander V. Chernikov }; 2253b23d5de9SAlexander V. Chernikov 22540bce0c23SAlexander V. Chernikov struct ta_buf_numarray 22550bce0c23SAlexander V. Chernikov { 22560bce0c23SAlexander V. Chernikov struct numarray na; 22570bce0c23SAlexander V. Chernikov }; 2258b23d5de9SAlexander V. Chernikov 2259b23d5de9SAlexander V. Chernikov int compare_numarray(const void *k, const void *v); 2260b23d5de9SAlexander V. Chernikov 2261b23d5de9SAlexander V. Chernikov int 2262b23d5de9SAlexander V. Chernikov compare_numarray(const void *k, const void *v) 2263b23d5de9SAlexander V. Chernikov { 2264b23d5de9SAlexander V. Chernikov struct numarray *na; 2265b23d5de9SAlexander V. Chernikov uint32_t key; 2266b23d5de9SAlexander V. Chernikov 2267b23d5de9SAlexander V. Chernikov key = *((uint32_t *)k); 2268b23d5de9SAlexander V. Chernikov na = (struct numarray *)v; 2269b23d5de9SAlexander V. Chernikov 2270b23d5de9SAlexander V. Chernikov if (key < na->number) 2271b23d5de9SAlexander V. Chernikov return (-1); 2272b23d5de9SAlexander V. Chernikov else if (key > na->number) 2273b23d5de9SAlexander V. Chernikov return (1); 2274b23d5de9SAlexander V. Chernikov 2275b23d5de9SAlexander V. Chernikov return (0); 2276b23d5de9SAlexander V. Chernikov } 2277b23d5de9SAlexander V. Chernikov 2278b23d5de9SAlexander V. Chernikov static struct numarray * 2279b23d5de9SAlexander V. Chernikov numarray_find(struct table_info *ti, void *key) 2280b23d5de9SAlexander V. Chernikov { 2281b23d5de9SAlexander V. Chernikov struct numarray *ri; 2282b23d5de9SAlexander V. Chernikov 2283b23d5de9SAlexander V. Chernikov ri = bsearch(key, ti->state, ti->data, sizeof(struct numarray), 2284b23d5de9SAlexander V. Chernikov compare_ifidx); 2285b23d5de9SAlexander V. Chernikov 2286b23d5de9SAlexander V. Chernikov return (ri); 2287b23d5de9SAlexander V. Chernikov } 2288b23d5de9SAlexander V. Chernikov 2289b23d5de9SAlexander V. Chernikov static int 2290b23d5de9SAlexander V. Chernikov ta_lookup_numarray(struct table_info *ti, void *key, uint32_t keylen, 2291b23d5de9SAlexander V. Chernikov uint32_t *val) 2292b23d5de9SAlexander V. Chernikov { 2293b23d5de9SAlexander V. Chernikov struct numarray *ri; 2294b23d5de9SAlexander V. Chernikov 2295b23d5de9SAlexander V. Chernikov ri = numarray_find(ti, key); 2296b23d5de9SAlexander V. Chernikov 2297b23d5de9SAlexander V. Chernikov if (ri != NULL) { 2298b23d5de9SAlexander V. Chernikov *val = ri->value; 2299b23d5de9SAlexander V. Chernikov return (1); 2300b23d5de9SAlexander V. Chernikov } 2301b23d5de9SAlexander V. Chernikov 2302b23d5de9SAlexander V. Chernikov return (0); 2303b23d5de9SAlexander V. Chernikov } 2304b23d5de9SAlexander V. Chernikov 2305b23d5de9SAlexander V. Chernikov static int 2306b23d5de9SAlexander V. Chernikov ta_init_numarray(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti, 2307914bffb6SAlexander V. Chernikov char *data, uint8_t tflags) 2308b23d5de9SAlexander V. Chernikov { 2309b23d5de9SAlexander V. Chernikov struct numarray_cfg *cfg; 2310b23d5de9SAlexander V. Chernikov 2311b23d5de9SAlexander V. Chernikov cfg = malloc(sizeof(*cfg), M_IPFW, M_WAITOK | M_ZERO); 2312b23d5de9SAlexander V. Chernikov 23130bce0c23SAlexander V. Chernikov cfg->size = 16; 2314b23d5de9SAlexander V. Chernikov cfg->main_ptr = malloc(sizeof(struct numarray) * cfg->size, M_IPFW, 2315b23d5de9SAlexander V. Chernikov M_WAITOK | M_ZERO); 2316b23d5de9SAlexander V. Chernikov 2317b23d5de9SAlexander V. Chernikov *ta_state = cfg; 2318b23d5de9SAlexander V. Chernikov ti->state = cfg->main_ptr; 2319b23d5de9SAlexander V. Chernikov ti->lookup = ta_lookup_numarray; 2320b23d5de9SAlexander V. Chernikov 2321b23d5de9SAlexander V. Chernikov return (0); 2322b23d5de9SAlexander V. Chernikov } 2323b23d5de9SAlexander V. Chernikov 2324b23d5de9SAlexander V. Chernikov /* 2325b23d5de9SAlexander V. Chernikov * Destroys table @ti 2326b23d5de9SAlexander V. Chernikov */ 2327b23d5de9SAlexander V. Chernikov static void 2328b23d5de9SAlexander V. Chernikov ta_destroy_numarray(void *ta_state, struct table_info *ti) 2329b23d5de9SAlexander V. Chernikov { 2330b23d5de9SAlexander V. Chernikov struct numarray_cfg *cfg; 2331b23d5de9SAlexander V. Chernikov 2332b23d5de9SAlexander V. Chernikov cfg = (struct numarray_cfg *)ta_state; 2333b23d5de9SAlexander V. Chernikov 2334b23d5de9SAlexander V. Chernikov if (cfg->main_ptr != NULL) 2335b23d5de9SAlexander V. Chernikov free(cfg->main_ptr, M_IPFW); 2336b23d5de9SAlexander V. Chernikov 2337b23d5de9SAlexander V. Chernikov free(cfg, M_IPFW); 2338b23d5de9SAlexander V. Chernikov } 2339b23d5de9SAlexander V. Chernikov 2340b23d5de9SAlexander V. Chernikov /* 23415f379342SAlexander V. Chernikov * Provide algo-specific table info 23425f379342SAlexander V. Chernikov */ 23435f379342SAlexander V. Chernikov static void 23445f379342SAlexander V. Chernikov ta_dump_numarray_tinfo(void *ta_state, struct table_info *ti, ipfw_ta_tinfo *tinfo) 23455f379342SAlexander V. Chernikov { 23465f379342SAlexander V. Chernikov struct numarray_cfg *cfg; 23475f379342SAlexander V. Chernikov 23485f379342SAlexander V. Chernikov cfg = (struct numarray_cfg *)ta_state; 23495f379342SAlexander V. Chernikov 23505f379342SAlexander V. Chernikov tinfo->taclass4 = IPFW_TACLASS_ARRAY; 23515f379342SAlexander V. Chernikov tinfo->size4 = cfg->size; 23525f379342SAlexander V. Chernikov tinfo->count4 = cfg->used; 23535f379342SAlexander V. Chernikov tinfo->itemsize4 = sizeof(struct numarray); 23545f379342SAlexander V. Chernikov } 23555f379342SAlexander V. Chernikov 23565f379342SAlexander V. Chernikov /* 2357b23d5de9SAlexander V. Chernikov * Prepare for addition/deletion to an array. 2358b23d5de9SAlexander V. Chernikov */ 2359b23d5de9SAlexander V. Chernikov static int 2360b23d5de9SAlexander V. Chernikov ta_prepare_add_numarray(struct ip_fw_chain *ch, struct tentry_info *tei, 2361b23d5de9SAlexander V. Chernikov void *ta_buf) 2362b23d5de9SAlexander V. Chernikov { 2363b23d5de9SAlexander V. Chernikov struct ta_buf_numarray *tb; 2364b23d5de9SAlexander V. Chernikov 2365b23d5de9SAlexander V. Chernikov tb = (struct ta_buf_numarray *)ta_buf; 2366b23d5de9SAlexander V. Chernikov 2367b23d5de9SAlexander V. Chernikov tb->na.number = *((uint32_t *)tei->paddr); 2368b23d5de9SAlexander V. Chernikov tb->na.value = tei->value; 2369b23d5de9SAlexander V. Chernikov 2370b23d5de9SAlexander V. Chernikov return (0); 2371b23d5de9SAlexander V. Chernikov } 2372b23d5de9SAlexander V. Chernikov 2373b23d5de9SAlexander V. Chernikov static int 2374b23d5de9SAlexander V. Chernikov ta_add_numarray(void *ta_state, struct table_info *ti, struct tentry_info *tei, 2375b6ee846eSAlexander V. Chernikov void *ta_buf, uint32_t *pnum) 2376b23d5de9SAlexander V. Chernikov { 2377b23d5de9SAlexander V. Chernikov struct numarray_cfg *cfg; 2378b23d5de9SAlexander V. Chernikov struct ta_buf_numarray *tb; 2379b23d5de9SAlexander V. Chernikov struct numarray *ri; 2380b23d5de9SAlexander V. Chernikov int res; 2381648e8380SAlexander V. Chernikov uint32_t value; 2382b23d5de9SAlexander V. Chernikov 2383b23d5de9SAlexander V. Chernikov tb = (struct ta_buf_numarray *)ta_buf; 2384b23d5de9SAlexander V. Chernikov cfg = (struct numarray_cfg *)ta_state; 2385b23d5de9SAlexander V. Chernikov 2386b23d5de9SAlexander V. Chernikov ri = numarray_find(ti, &tb->na.number); 2387b23d5de9SAlexander V. Chernikov 2388b23d5de9SAlexander V. Chernikov if (ri != NULL) { 2389b23d5de9SAlexander V. Chernikov if ((tei->flags & TEI_FLAGS_UPDATE) == 0) 2390b23d5de9SAlexander V. Chernikov return (EEXIST); 2391b23d5de9SAlexander V. Chernikov 2392648e8380SAlexander V. Chernikov /* Exchange values between ri and @tei */ 2393648e8380SAlexander V. Chernikov value = ri->value; 2394648e8380SAlexander V. Chernikov ri->value = tei->value; 2395648e8380SAlexander V. Chernikov tei->value = value; 2396b23d5de9SAlexander V. Chernikov /* Indicate that update has happened instead of addition */ 2397b23d5de9SAlexander V. Chernikov tei->flags |= TEI_FLAGS_UPDATED; 2398b23d5de9SAlexander V. Chernikov *pnum = 0; 2399b23d5de9SAlexander V. Chernikov return (0); 2400b23d5de9SAlexander V. Chernikov } 2401b23d5de9SAlexander V. Chernikov 24024c0c07a5SAlexander V. Chernikov if ((tei->flags & TEI_FLAGS_DONTADD) != 0) 24034c0c07a5SAlexander V. Chernikov return (EFBIG); 24044c0c07a5SAlexander V. Chernikov 2405b23d5de9SAlexander V. Chernikov res = badd(&tb->na.number, &tb->na, cfg->main_ptr, cfg->used, 2406b23d5de9SAlexander V. Chernikov sizeof(struct numarray), compare_numarray); 2407b23d5de9SAlexander V. Chernikov 2408b23d5de9SAlexander V. Chernikov KASSERT(res == 1, ("number %d already exists", tb->na.number)); 2409b23d5de9SAlexander V. Chernikov cfg->used++; 2410b23d5de9SAlexander V. Chernikov ti->data = cfg->used; 2411b23d5de9SAlexander V. Chernikov *pnum = 1; 2412b23d5de9SAlexander V. Chernikov 2413b23d5de9SAlexander V. Chernikov return (0); 2414b23d5de9SAlexander V. Chernikov } 2415b23d5de9SAlexander V. Chernikov 2416b23d5de9SAlexander V. Chernikov /* 2417b23d5de9SAlexander V. Chernikov * Remove key from both configuration list and 2418b23d5de9SAlexander V. Chernikov * runtime array. Removed interface notification. 2419b23d5de9SAlexander V. Chernikov */ 2420b23d5de9SAlexander V. Chernikov static int 2421b23d5de9SAlexander V. Chernikov ta_del_numarray(void *ta_state, struct table_info *ti, struct tentry_info *tei, 2422b6ee846eSAlexander V. Chernikov void *ta_buf, uint32_t *pnum) 2423b23d5de9SAlexander V. Chernikov { 2424b23d5de9SAlexander V. Chernikov struct numarray_cfg *cfg; 2425b23d5de9SAlexander V. Chernikov struct ta_buf_numarray *tb; 2426b23d5de9SAlexander V. Chernikov struct numarray *ri; 2427b23d5de9SAlexander V. Chernikov int res; 2428b23d5de9SAlexander V. Chernikov 2429b23d5de9SAlexander V. Chernikov tb = (struct ta_buf_numarray *)ta_buf; 2430b23d5de9SAlexander V. Chernikov cfg = (struct numarray_cfg *)ta_state; 2431b23d5de9SAlexander V. Chernikov 2432b23d5de9SAlexander V. Chernikov ri = numarray_find(ti, &tb->na.number); 2433b23d5de9SAlexander V. Chernikov if (ri == NULL) 2434b23d5de9SAlexander V. Chernikov return (ENOENT); 2435b23d5de9SAlexander V. Chernikov 2436648e8380SAlexander V. Chernikov tei->value = ri->value; 2437648e8380SAlexander V. Chernikov 2438b23d5de9SAlexander V. Chernikov res = bdel(&tb->na.number, cfg->main_ptr, cfg->used, 2439b23d5de9SAlexander V. Chernikov sizeof(struct numarray), compare_numarray); 2440b23d5de9SAlexander V. Chernikov 2441b23d5de9SAlexander V. Chernikov KASSERT(res == 1, ("number %u does not exist", tb->na.number)); 2442b23d5de9SAlexander V. Chernikov cfg->used--; 2443b23d5de9SAlexander V. Chernikov ti->data = cfg->used; 2444b23d5de9SAlexander V. Chernikov *pnum = 1; 2445b23d5de9SAlexander V. Chernikov 2446b23d5de9SAlexander V. Chernikov return (0); 2447b23d5de9SAlexander V. Chernikov } 2448b23d5de9SAlexander V. Chernikov 2449b23d5de9SAlexander V. Chernikov static void 2450b23d5de9SAlexander V. Chernikov ta_flush_numarray_entry(struct ip_fw_chain *ch, struct tentry_info *tei, 2451b23d5de9SAlexander V. Chernikov void *ta_buf) 2452b23d5de9SAlexander V. Chernikov { 2453b23d5de9SAlexander V. Chernikov 24540bce0c23SAlexander V. Chernikov /* We don't have any state, do nothing */ 2455b23d5de9SAlexander V. Chernikov } 2456b23d5de9SAlexander V. Chernikov 2457b23d5de9SAlexander V. Chernikov 2458b23d5de9SAlexander V. Chernikov /* 2459b23d5de9SAlexander V. Chernikov * Table growing callbacks. 2460b23d5de9SAlexander V. Chernikov */ 2461b23d5de9SAlexander V. Chernikov 2462b6ee846eSAlexander V. Chernikov static int 2463b6ee846eSAlexander V. Chernikov ta_has_space_numarray(void *ta_state, struct table_info *ti, uint32_t count, 2464b6ee846eSAlexander V. Chernikov uint64_t *pflags) 2465b6ee846eSAlexander V. Chernikov { 2466b6ee846eSAlexander V. Chernikov struct numarray_cfg *cfg; 24670bce0c23SAlexander V. Chernikov size_t size; 2468b6ee846eSAlexander V. Chernikov 2469b6ee846eSAlexander V. Chernikov cfg = (struct numarray_cfg *)ta_state; 2470b6ee846eSAlexander V. Chernikov 24710bce0c23SAlexander V. Chernikov size = cfg->size; 24720bce0c23SAlexander V. Chernikov while (size < cfg->used + count) 24730bce0c23SAlexander V. Chernikov size *= 2; 24740bce0c23SAlexander V. Chernikov 24750bce0c23SAlexander V. Chernikov if (size != cfg->size) { 24760bce0c23SAlexander V. Chernikov *pflags = size; 2477b6ee846eSAlexander V. Chernikov return (0); 2478b6ee846eSAlexander V. Chernikov } 2479b6ee846eSAlexander V. Chernikov 2480b6ee846eSAlexander V. Chernikov return (1); 2481b6ee846eSAlexander V. Chernikov } 2482b6ee846eSAlexander V. Chernikov 2483b23d5de9SAlexander V. Chernikov /* 2484b6ee846eSAlexander V. Chernikov * Allocate new, larger runtime array. 2485b23d5de9SAlexander V. Chernikov */ 2486b23d5de9SAlexander V. Chernikov static int 2487b23d5de9SAlexander V. Chernikov ta_prepare_mod_numarray(void *ta_buf, uint64_t *pflags) 2488b23d5de9SAlexander V. Chernikov { 2489b23d5de9SAlexander V. Chernikov struct mod_item *mi; 2490b23d5de9SAlexander V. Chernikov 2491b23d5de9SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 2492b23d5de9SAlexander V. Chernikov 2493b23d5de9SAlexander V. Chernikov memset(mi, 0, sizeof(struct mod_item)); 2494b23d5de9SAlexander V. Chernikov mi->size = *pflags; 2495b23d5de9SAlexander V. Chernikov mi->main_ptr = malloc(sizeof(struct numarray) * mi->size, M_IPFW, 2496b23d5de9SAlexander V. Chernikov M_WAITOK | M_ZERO); 2497b23d5de9SAlexander V. Chernikov 2498b23d5de9SAlexander V. Chernikov return (0); 2499b23d5de9SAlexander V. Chernikov } 2500b23d5de9SAlexander V. Chernikov 2501b23d5de9SAlexander V. Chernikov /* 2502b23d5de9SAlexander V. Chernikov * Copy data from old runtime array to new one. 2503b23d5de9SAlexander V. Chernikov */ 2504b23d5de9SAlexander V. Chernikov static int 2505b23d5de9SAlexander V. Chernikov ta_fill_mod_numarray(void *ta_state, struct table_info *ti, void *ta_buf, 2506b23d5de9SAlexander V. Chernikov uint64_t *pflags) 2507b23d5de9SAlexander V. Chernikov { 2508b23d5de9SAlexander V. Chernikov struct mod_item *mi; 2509b23d5de9SAlexander V. Chernikov struct numarray_cfg *cfg; 2510b23d5de9SAlexander V. Chernikov 2511b23d5de9SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 2512b23d5de9SAlexander V. Chernikov cfg = (struct numarray_cfg *)ta_state; 2513b23d5de9SAlexander V. Chernikov 2514b23d5de9SAlexander V. Chernikov /* Check if we still need to grow array */ 2515b23d5de9SAlexander V. Chernikov if (cfg->size >= mi->size) { 2516b23d5de9SAlexander V. Chernikov *pflags = 0; 2517b23d5de9SAlexander V. Chernikov return (0); 2518b23d5de9SAlexander V. Chernikov } 2519b23d5de9SAlexander V. Chernikov 2520b23d5de9SAlexander V. Chernikov memcpy(mi->main_ptr, cfg->main_ptr, cfg->used * sizeof(struct numarray)); 2521b23d5de9SAlexander V. Chernikov 2522b23d5de9SAlexander V. Chernikov return (0); 2523b23d5de9SAlexander V. Chernikov } 2524b23d5de9SAlexander V. Chernikov 2525b23d5de9SAlexander V. Chernikov /* 2526b23d5de9SAlexander V. Chernikov * Switch old & new arrays. 2527b23d5de9SAlexander V. Chernikov */ 2528b23d5de9SAlexander V. Chernikov static int 2529b23d5de9SAlexander V. Chernikov ta_modify_numarray(void *ta_state, struct table_info *ti, void *ta_buf, 2530b23d5de9SAlexander V. Chernikov uint64_t pflags) 2531b23d5de9SAlexander V. Chernikov { 2532b23d5de9SAlexander V. Chernikov struct mod_item *mi; 2533b23d5de9SAlexander V. Chernikov struct numarray_cfg *cfg; 2534b23d5de9SAlexander V. Chernikov void *old_ptr; 2535b23d5de9SAlexander V. Chernikov 2536b23d5de9SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 2537b23d5de9SAlexander V. Chernikov cfg = (struct numarray_cfg *)ta_state; 2538b23d5de9SAlexander V. Chernikov 2539b23d5de9SAlexander V. Chernikov old_ptr = cfg->main_ptr; 2540b23d5de9SAlexander V. Chernikov cfg->main_ptr = mi->main_ptr; 2541b23d5de9SAlexander V. Chernikov cfg->size = mi->size; 2542b23d5de9SAlexander V. Chernikov ti->state = cfg->main_ptr; 2543b23d5de9SAlexander V. Chernikov 2544b23d5de9SAlexander V. Chernikov mi->main_ptr = old_ptr; 2545b23d5de9SAlexander V. Chernikov 2546b23d5de9SAlexander V. Chernikov return (0); 2547b23d5de9SAlexander V. Chernikov } 2548b23d5de9SAlexander V. Chernikov 2549b23d5de9SAlexander V. Chernikov /* 2550b23d5de9SAlexander V. Chernikov * Free unneded array. 2551b23d5de9SAlexander V. Chernikov */ 2552b23d5de9SAlexander V. Chernikov static void 2553b23d5de9SAlexander V. Chernikov ta_flush_mod_numarray(void *ta_buf) 2554b23d5de9SAlexander V. Chernikov { 2555b23d5de9SAlexander V. Chernikov struct mod_item *mi; 2556b23d5de9SAlexander V. Chernikov 2557b23d5de9SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 2558b23d5de9SAlexander V. Chernikov if (mi->main_ptr != NULL) 2559b23d5de9SAlexander V. Chernikov free(mi->main_ptr, M_IPFW); 2560b23d5de9SAlexander V. Chernikov } 2561b23d5de9SAlexander V. Chernikov 2562b23d5de9SAlexander V. Chernikov static int 2563b23d5de9SAlexander V. Chernikov ta_dump_numarray_tentry(void *ta_state, struct table_info *ti, void *e, 2564b23d5de9SAlexander V. Chernikov ipfw_obj_tentry *tent) 2565b23d5de9SAlexander V. Chernikov { 2566b23d5de9SAlexander V. Chernikov struct numarray *na; 2567b23d5de9SAlexander V. Chernikov 2568b23d5de9SAlexander V. Chernikov na = (struct numarray *)e; 2569b23d5de9SAlexander V. Chernikov 2570b23d5de9SAlexander V. Chernikov tent->k.key = na->number; 2571b23d5de9SAlexander V. Chernikov tent->value = na->value; 2572b23d5de9SAlexander V. Chernikov 2573b23d5de9SAlexander V. Chernikov return (0); 2574b23d5de9SAlexander V. Chernikov } 2575b23d5de9SAlexander V. Chernikov 2576b23d5de9SAlexander V. Chernikov static int 2577914bffb6SAlexander V. Chernikov ta_find_numarray_tentry(void *ta_state, struct table_info *ti, 2578914bffb6SAlexander V. Chernikov ipfw_obj_tentry *tent) 2579b23d5de9SAlexander V. Chernikov { 2580b23d5de9SAlexander V. Chernikov struct numarray_cfg *cfg; 2581b23d5de9SAlexander V. Chernikov struct numarray *ri; 2582b23d5de9SAlexander V. Chernikov 2583b23d5de9SAlexander V. Chernikov cfg = (struct numarray_cfg *)ta_state; 2584b23d5de9SAlexander V. Chernikov 2585914bffb6SAlexander V. Chernikov ri = numarray_find(ti, &tent->k.key); 2586b23d5de9SAlexander V. Chernikov 2587b23d5de9SAlexander V. Chernikov if (ri != NULL) { 2588b23d5de9SAlexander V. Chernikov ta_dump_numarray_tentry(ta_state, ti, ri, tent); 2589b23d5de9SAlexander V. Chernikov return (0); 2590b23d5de9SAlexander V. Chernikov } 2591b23d5de9SAlexander V. Chernikov 2592b23d5de9SAlexander V. Chernikov return (ENOENT); 2593b23d5de9SAlexander V. Chernikov } 2594b23d5de9SAlexander V. Chernikov 2595b23d5de9SAlexander V. Chernikov static void 2596b23d5de9SAlexander V. Chernikov ta_foreach_numarray(void *ta_state, struct table_info *ti, ta_foreach_f *f, 2597b23d5de9SAlexander V. Chernikov void *arg) 2598b23d5de9SAlexander V. Chernikov { 2599b23d5de9SAlexander V. Chernikov struct numarray_cfg *cfg; 2600b23d5de9SAlexander V. Chernikov struct numarray *array; 2601b23d5de9SAlexander V. Chernikov int i; 2602b23d5de9SAlexander V. Chernikov 2603b23d5de9SAlexander V. Chernikov cfg = (struct numarray_cfg *)ta_state; 2604b23d5de9SAlexander V. Chernikov array = cfg->main_ptr; 2605b23d5de9SAlexander V. Chernikov 2606b23d5de9SAlexander V. Chernikov for (i = 0; i < cfg->used; i++) 2607b23d5de9SAlexander V. Chernikov f(&array[i], arg); 2608b23d5de9SAlexander V. Chernikov } 2609b23d5de9SAlexander V. Chernikov 2610b23d5de9SAlexander V. Chernikov struct table_algo number_array = { 2611b23d5de9SAlexander V. Chernikov .name = "number:array", 2612b23d5de9SAlexander V. Chernikov .type = IPFW_TABLE_NUMBER, 261357a1cf95SAlexander V. Chernikov .ta_buf_size = sizeof(struct ta_buf_numarray), 2614b23d5de9SAlexander V. Chernikov .init = ta_init_numarray, 2615b23d5de9SAlexander V. Chernikov .destroy = ta_destroy_numarray, 2616b23d5de9SAlexander V. Chernikov .prepare_add = ta_prepare_add_numarray, 2617b23d5de9SAlexander V. Chernikov .prepare_del = ta_prepare_add_numarray, 2618b23d5de9SAlexander V. Chernikov .add = ta_add_numarray, 2619b23d5de9SAlexander V. Chernikov .del = ta_del_numarray, 2620b23d5de9SAlexander V. Chernikov .flush_entry = ta_flush_numarray_entry, 2621b23d5de9SAlexander V. Chernikov .foreach = ta_foreach_numarray, 2622b23d5de9SAlexander V. Chernikov .dump_tentry = ta_dump_numarray_tentry, 2623b23d5de9SAlexander V. Chernikov .find_tentry = ta_find_numarray_tentry, 26245f379342SAlexander V. Chernikov .dump_tinfo = ta_dump_numarray_tinfo, 2625b6ee846eSAlexander V. Chernikov .has_space = ta_has_space_numarray, 2626b23d5de9SAlexander V. Chernikov .prepare_mod = ta_prepare_mod_numarray, 2627b23d5de9SAlexander V. Chernikov .fill_mod = ta_fill_mod_numarray, 2628b23d5de9SAlexander V. Chernikov .modify = ta_modify_numarray, 2629b23d5de9SAlexander V. Chernikov .flush_mod = ta_flush_mod_numarray, 2630b23d5de9SAlexander V. Chernikov }; 2631b23d5de9SAlexander V. Chernikov 2632914bffb6SAlexander V. Chernikov /* 2633914bffb6SAlexander V. Chernikov * flow:hash cmds 2634914bffb6SAlexander V. Chernikov * 2635914bffb6SAlexander V. Chernikov * 2636914bffb6SAlexander V. Chernikov * ti->data: 2637914bffb6SAlexander V. Chernikov * [inv.mask4][inv.mask6][log2hsize4][log2hsize6] 2638914bffb6SAlexander V. Chernikov * [ 8][ 8[ 8][ 8] 2639914bffb6SAlexander V. Chernikov * 2640914bffb6SAlexander V. Chernikov * inv.mask4: 32 - mask 2641914bffb6SAlexander V. Chernikov * inv.mask6: 2642914bffb6SAlexander V. Chernikov * 1) _slow lookup: mask 2643914bffb6SAlexander V. Chernikov * 2) _aligned: (128 - mask) / 8 2644914bffb6SAlexander V. Chernikov * 3) _64: 8 2645914bffb6SAlexander V. Chernikov * 2646914bffb6SAlexander V. Chernikov * 2647914bffb6SAlexander V. Chernikov * pflags: 2648b6ee846eSAlexander V. Chernikov * [hsize4][hsize6] 2649b6ee846eSAlexander V. Chernikov * [ 16][ 16] 2650914bffb6SAlexander V. Chernikov */ 2651914bffb6SAlexander V. Chernikov 2652914bffb6SAlexander V. Chernikov struct fhashentry; 2653914bffb6SAlexander V. Chernikov 2654914bffb6SAlexander V. Chernikov SLIST_HEAD(fhashbhead, fhashentry); 2655914bffb6SAlexander V. Chernikov 2656914bffb6SAlexander V. Chernikov struct fhashentry { 2657914bffb6SAlexander V. Chernikov SLIST_ENTRY(fhashentry) next; 2658914bffb6SAlexander V. Chernikov uint8_t af; 2659914bffb6SAlexander V. Chernikov uint8_t proto; 2660914bffb6SAlexander V. Chernikov uint16_t spare0; 2661914bffb6SAlexander V. Chernikov uint16_t dport; 2662914bffb6SAlexander V. Chernikov uint16_t sport; 2663914bffb6SAlexander V. Chernikov uint32_t value; 2664914bffb6SAlexander V. Chernikov uint32_t spare1; 2665914bffb6SAlexander V. Chernikov }; 2666914bffb6SAlexander V. Chernikov 2667914bffb6SAlexander V. Chernikov struct fhashentry4 { 2668914bffb6SAlexander V. Chernikov struct fhashentry e; 2669914bffb6SAlexander V. Chernikov struct in_addr dip; 2670914bffb6SAlexander V. Chernikov struct in_addr sip; 2671914bffb6SAlexander V. Chernikov }; 2672914bffb6SAlexander V. Chernikov 2673914bffb6SAlexander V. Chernikov struct fhashentry6 { 2674914bffb6SAlexander V. Chernikov struct fhashentry e; 2675914bffb6SAlexander V. Chernikov struct in6_addr dip6; 2676914bffb6SAlexander V. Chernikov struct in6_addr sip6; 2677914bffb6SAlexander V. Chernikov }; 2678914bffb6SAlexander V. Chernikov 2679914bffb6SAlexander V. Chernikov struct fhash_cfg { 2680914bffb6SAlexander V. Chernikov struct fhashbhead *head; 2681914bffb6SAlexander V. Chernikov size_t size; 2682914bffb6SAlexander V. Chernikov size_t items; 2683914bffb6SAlexander V. Chernikov struct fhashentry4 fe4; 2684914bffb6SAlexander V. Chernikov struct fhashentry6 fe6; 2685914bffb6SAlexander V. Chernikov }; 2686914bffb6SAlexander V. Chernikov 26873fe2ef91SAlexander V. Chernikov struct ta_buf_fhash { 26880bce0c23SAlexander V. Chernikov void *ent_ptr; 26890bce0c23SAlexander V. Chernikov struct fhashentry6 fe6; 26900bce0c23SAlexander V. Chernikov }; 26910bce0c23SAlexander V. Chernikov 2692914bffb6SAlexander V. Chernikov static __inline int 2693914bffb6SAlexander V. Chernikov cmp_flow_ent(struct fhashentry *a, struct fhashentry *b, size_t sz) 2694914bffb6SAlexander V. Chernikov { 2695914bffb6SAlexander V. Chernikov uint64_t *ka, *kb; 2696914bffb6SAlexander V. Chernikov 2697914bffb6SAlexander V. Chernikov ka = (uint64_t *)(&a->next + 1); 2698914bffb6SAlexander V. Chernikov kb = (uint64_t *)(&b->next + 1); 2699914bffb6SAlexander V. Chernikov 2700914bffb6SAlexander V. Chernikov if (*ka == *kb && (memcmp(a + 1, b + 1, sz) == 0)) 2701914bffb6SAlexander V. Chernikov return (1); 2702914bffb6SAlexander V. Chernikov 2703914bffb6SAlexander V. Chernikov return (0); 2704914bffb6SAlexander V. Chernikov } 2705914bffb6SAlexander V. Chernikov 2706914bffb6SAlexander V. Chernikov static __inline uint32_t 2707914bffb6SAlexander V. Chernikov hash_flow4(struct fhashentry4 *f, int hsize) 2708914bffb6SAlexander V. Chernikov { 2709914bffb6SAlexander V. Chernikov uint32_t i; 2710914bffb6SAlexander V. Chernikov 2711914bffb6SAlexander V. Chernikov i = (f->dip.s_addr) ^ (f->sip.s_addr) ^ (f->e.dport) ^ (f->e.sport); 2712914bffb6SAlexander V. Chernikov 2713914bffb6SAlexander V. Chernikov return (i % (hsize - 1)); 2714914bffb6SAlexander V. Chernikov } 2715914bffb6SAlexander V. Chernikov 2716914bffb6SAlexander V. Chernikov static __inline uint32_t 2717914bffb6SAlexander V. Chernikov hash_flow6(struct fhashentry6 *f, int hsize) 2718914bffb6SAlexander V. Chernikov { 2719914bffb6SAlexander V. Chernikov uint32_t i; 2720914bffb6SAlexander V. Chernikov 2721914bffb6SAlexander V. Chernikov i = (f->dip6.__u6_addr.__u6_addr32[2]) ^ 2722914bffb6SAlexander V. Chernikov (f->dip6.__u6_addr.__u6_addr32[3]) ^ 2723914bffb6SAlexander V. Chernikov (f->sip6.__u6_addr.__u6_addr32[2]) ^ 2724914bffb6SAlexander V. Chernikov (f->sip6.__u6_addr.__u6_addr32[3]) ^ 2725914bffb6SAlexander V. Chernikov (f->e.dport) ^ (f->e.sport); 2726914bffb6SAlexander V. Chernikov 2727914bffb6SAlexander V. Chernikov return (i % (hsize - 1)); 2728914bffb6SAlexander V. Chernikov } 2729914bffb6SAlexander V. Chernikov 2730914bffb6SAlexander V. Chernikov static uint32_t 2731914bffb6SAlexander V. Chernikov hash_flow_ent(struct fhashentry *ent, uint32_t size) 2732914bffb6SAlexander V. Chernikov { 2733914bffb6SAlexander V. Chernikov uint32_t hash; 2734914bffb6SAlexander V. Chernikov 2735914bffb6SAlexander V. Chernikov if (ent->af == AF_INET) { 2736914bffb6SAlexander V. Chernikov hash = hash_flow4((struct fhashentry4 *)ent, size); 2737914bffb6SAlexander V. Chernikov } else { 2738914bffb6SAlexander V. Chernikov hash = hash_flow6((struct fhashentry6 *)ent, size); 2739914bffb6SAlexander V. Chernikov } 2740914bffb6SAlexander V. Chernikov 2741914bffb6SAlexander V. Chernikov return (hash); 2742914bffb6SAlexander V. Chernikov } 2743914bffb6SAlexander V. Chernikov 2744914bffb6SAlexander V. Chernikov static int 2745914bffb6SAlexander V. Chernikov ta_lookup_fhash(struct table_info *ti, void *key, uint32_t keylen, 2746914bffb6SAlexander V. Chernikov uint32_t *val) 2747914bffb6SAlexander V. Chernikov { 2748914bffb6SAlexander V. Chernikov struct fhashbhead *head; 2749914bffb6SAlexander V. Chernikov struct fhashentry *ent; 2750914bffb6SAlexander V. Chernikov struct fhashentry4 *m4; 2751914bffb6SAlexander V. Chernikov struct ipfw_flow_id *id; 2752914bffb6SAlexander V. Chernikov uint16_t hash, hsize; 2753914bffb6SAlexander V. Chernikov 2754914bffb6SAlexander V. Chernikov id = (struct ipfw_flow_id *)key; 2755914bffb6SAlexander V. Chernikov head = (struct fhashbhead *)ti->state; 2756914bffb6SAlexander V. Chernikov hsize = ti->data; 2757914bffb6SAlexander V. Chernikov m4 = (struct fhashentry4 *)ti->xstate; 2758914bffb6SAlexander V. Chernikov 2759914bffb6SAlexander V. Chernikov if (id->addr_type == 4) { 2760914bffb6SAlexander V. Chernikov struct fhashentry4 f; 2761914bffb6SAlexander V. Chernikov 2762914bffb6SAlexander V. Chernikov /* Copy hash mask */ 2763914bffb6SAlexander V. Chernikov f = *m4; 2764914bffb6SAlexander V. Chernikov 2765914bffb6SAlexander V. Chernikov f.dip.s_addr &= id->dst_ip; 2766914bffb6SAlexander V. Chernikov f.sip.s_addr &= id->src_ip; 2767914bffb6SAlexander V. Chernikov f.e.dport &= id->dst_port; 2768914bffb6SAlexander V. Chernikov f.e.sport &= id->src_port; 2769914bffb6SAlexander V. Chernikov f.e.proto &= id->proto; 2770914bffb6SAlexander V. Chernikov hash = hash_flow4(&f, hsize); 2771914bffb6SAlexander V. Chernikov SLIST_FOREACH(ent, &head[hash], next) { 2772914bffb6SAlexander V. Chernikov if (cmp_flow_ent(ent, &f.e, 2 * 4) != 0) { 2773914bffb6SAlexander V. Chernikov *val = ent->value; 2774914bffb6SAlexander V. Chernikov return (1); 2775914bffb6SAlexander V. Chernikov } 2776914bffb6SAlexander V. Chernikov } 2777914bffb6SAlexander V. Chernikov } else if (id->addr_type == 6) { 2778914bffb6SAlexander V. Chernikov struct fhashentry6 f; 2779914bffb6SAlexander V. Chernikov uint64_t *fp, *idp; 2780914bffb6SAlexander V. Chernikov 2781914bffb6SAlexander V. Chernikov /* Copy hash mask */ 2782914bffb6SAlexander V. Chernikov f = *((struct fhashentry6 *)(m4 + 1)); 2783914bffb6SAlexander V. Chernikov 2784914bffb6SAlexander V. Chernikov /* Handle lack of __u6_addr.__u6_addr64 */ 2785914bffb6SAlexander V. Chernikov fp = (uint64_t *)&f.dip6; 2786914bffb6SAlexander V. Chernikov idp = (uint64_t *)&id->dst_ip6; 2787914bffb6SAlexander V. Chernikov /* src IPv6 is stored after dst IPv6 */ 2788914bffb6SAlexander V. Chernikov *fp++ &= *idp++; 2789914bffb6SAlexander V. Chernikov *fp++ &= *idp++; 2790914bffb6SAlexander V. Chernikov *fp++ &= *idp++; 2791914bffb6SAlexander V. Chernikov *fp &= *idp; 2792914bffb6SAlexander V. Chernikov f.e.dport &= id->dst_port; 2793914bffb6SAlexander V. Chernikov f.e.sport &= id->src_port; 2794914bffb6SAlexander V. Chernikov f.e.proto &= id->proto; 2795914bffb6SAlexander V. Chernikov hash = hash_flow6(&f, hsize); 2796914bffb6SAlexander V. Chernikov SLIST_FOREACH(ent, &head[hash], next) { 2797914bffb6SAlexander V. Chernikov if (cmp_flow_ent(ent, &f.e, 2 * 16) != 0) { 2798914bffb6SAlexander V. Chernikov *val = ent->value; 2799914bffb6SAlexander V. Chernikov return (1); 2800914bffb6SAlexander V. Chernikov } 2801914bffb6SAlexander V. Chernikov } 2802914bffb6SAlexander V. Chernikov } 2803914bffb6SAlexander V. Chernikov 2804914bffb6SAlexander V. Chernikov return (0); 2805914bffb6SAlexander V. Chernikov } 2806914bffb6SAlexander V. Chernikov 2807914bffb6SAlexander V. Chernikov /* 2808914bffb6SAlexander V. Chernikov * New table. 2809914bffb6SAlexander V. Chernikov */ 2810914bffb6SAlexander V. Chernikov static int 2811914bffb6SAlexander V. Chernikov ta_init_fhash(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti, 2812914bffb6SAlexander V. Chernikov char *data, uint8_t tflags) 2813914bffb6SAlexander V. Chernikov { 2814914bffb6SAlexander V. Chernikov int i; 2815914bffb6SAlexander V. Chernikov struct fhash_cfg *cfg; 2816914bffb6SAlexander V. Chernikov struct fhashentry4 *fe4; 2817914bffb6SAlexander V. Chernikov struct fhashentry6 *fe6; 2818914bffb6SAlexander V. Chernikov 2819914bffb6SAlexander V. Chernikov cfg = malloc(sizeof(struct fhash_cfg), M_IPFW, M_WAITOK | M_ZERO); 2820914bffb6SAlexander V. Chernikov 2821914bffb6SAlexander V. Chernikov cfg->size = 512; 2822914bffb6SAlexander V. Chernikov 2823914bffb6SAlexander V. Chernikov cfg->head = malloc(sizeof(struct fhashbhead) * cfg->size, M_IPFW, 2824914bffb6SAlexander V. Chernikov M_WAITOK | M_ZERO); 2825914bffb6SAlexander V. Chernikov for (i = 0; i < cfg->size; i++) 2826914bffb6SAlexander V. Chernikov SLIST_INIT(&cfg->head[i]); 2827914bffb6SAlexander V. Chernikov 2828914bffb6SAlexander V. Chernikov /* Fill in fe masks based on @tflags */ 2829914bffb6SAlexander V. Chernikov fe4 = &cfg->fe4; 2830914bffb6SAlexander V. Chernikov fe6 = &cfg->fe6; 2831914bffb6SAlexander V. Chernikov if (tflags & IPFW_TFFLAG_SRCIP) { 2832914bffb6SAlexander V. Chernikov memset(&fe4->sip, 0xFF, sizeof(fe4->sip)); 2833914bffb6SAlexander V. Chernikov memset(&fe6->sip6, 0xFF, sizeof(fe6->sip6)); 2834914bffb6SAlexander V. Chernikov } 2835914bffb6SAlexander V. Chernikov if (tflags & IPFW_TFFLAG_DSTIP) { 2836914bffb6SAlexander V. Chernikov memset(&fe4->dip, 0xFF, sizeof(fe4->dip)); 2837914bffb6SAlexander V. Chernikov memset(&fe6->dip6, 0xFF, sizeof(fe6->dip6)); 2838914bffb6SAlexander V. Chernikov } 2839914bffb6SAlexander V. Chernikov if (tflags & IPFW_TFFLAG_SRCPORT) { 2840914bffb6SAlexander V. Chernikov memset(&fe4->e.sport, 0xFF, sizeof(fe4->e.sport)); 2841914bffb6SAlexander V. Chernikov memset(&fe6->e.sport, 0xFF, sizeof(fe6->e.sport)); 2842914bffb6SAlexander V. Chernikov } 2843914bffb6SAlexander V. Chernikov if (tflags & IPFW_TFFLAG_DSTPORT) { 2844914bffb6SAlexander V. Chernikov memset(&fe4->e.dport, 0xFF, sizeof(fe4->e.dport)); 2845914bffb6SAlexander V. Chernikov memset(&fe6->e.dport, 0xFF, sizeof(fe6->e.dport)); 2846914bffb6SAlexander V. Chernikov } 2847914bffb6SAlexander V. Chernikov if (tflags & IPFW_TFFLAG_PROTO) { 2848914bffb6SAlexander V. Chernikov memset(&fe4->e.proto, 0xFF, sizeof(fe4->e.proto)); 2849914bffb6SAlexander V. Chernikov memset(&fe6->e.proto, 0xFF, sizeof(fe6->e.proto)); 2850914bffb6SAlexander V. Chernikov } 2851914bffb6SAlexander V. Chernikov 2852914bffb6SAlexander V. Chernikov fe4->e.af = AF_INET; 2853914bffb6SAlexander V. Chernikov fe6->e.af = AF_INET6; 2854914bffb6SAlexander V. Chernikov 2855914bffb6SAlexander V. Chernikov *ta_state = cfg; 2856914bffb6SAlexander V. Chernikov ti->state = cfg->head; 2857914bffb6SAlexander V. Chernikov ti->xstate = &cfg->fe4; 2858914bffb6SAlexander V. Chernikov ti->data = cfg->size; 2859914bffb6SAlexander V. Chernikov ti->lookup = ta_lookup_fhash; 2860914bffb6SAlexander V. Chernikov 2861914bffb6SAlexander V. Chernikov return (0); 2862914bffb6SAlexander V. Chernikov } 2863914bffb6SAlexander V. Chernikov 2864914bffb6SAlexander V. Chernikov static void 2865914bffb6SAlexander V. Chernikov ta_destroy_fhash(void *ta_state, struct table_info *ti) 2866914bffb6SAlexander V. Chernikov { 2867914bffb6SAlexander V. Chernikov struct fhash_cfg *cfg; 2868914bffb6SAlexander V. Chernikov struct fhashentry *ent, *ent_next; 2869914bffb6SAlexander V. Chernikov int i; 2870914bffb6SAlexander V. Chernikov 2871914bffb6SAlexander V. Chernikov cfg = (struct fhash_cfg *)ta_state; 2872914bffb6SAlexander V. Chernikov 2873914bffb6SAlexander V. Chernikov for (i = 0; i < cfg->size; i++) 2874914bffb6SAlexander V. Chernikov SLIST_FOREACH_SAFE(ent, &cfg->head[i], next, ent_next) 2875914bffb6SAlexander V. Chernikov free(ent, M_IPFW_TBL); 2876914bffb6SAlexander V. Chernikov 2877914bffb6SAlexander V. Chernikov free(cfg->head, M_IPFW); 2878914bffb6SAlexander V. Chernikov free(cfg, M_IPFW); 2879914bffb6SAlexander V. Chernikov } 2880914bffb6SAlexander V. Chernikov 28815f379342SAlexander V. Chernikov /* 28825f379342SAlexander V. Chernikov * Provide algo-specific table info 28835f379342SAlexander V. Chernikov */ 28845f379342SAlexander V. Chernikov static void 28855f379342SAlexander V. Chernikov ta_dump_fhash_tinfo(void *ta_state, struct table_info *ti, ipfw_ta_tinfo *tinfo) 28865f379342SAlexander V. Chernikov { 28875f379342SAlexander V. Chernikov struct fhash_cfg *cfg; 28885f379342SAlexander V. Chernikov 28895f379342SAlexander V. Chernikov cfg = (struct fhash_cfg *)ta_state; 28905f379342SAlexander V. Chernikov 28915f379342SAlexander V. Chernikov tinfo->flags = IPFW_TATFLAGS_AFITEM; 28925f379342SAlexander V. Chernikov tinfo->taclass4 = IPFW_TACLASS_HASH; 28935f379342SAlexander V. Chernikov tinfo->size4 = cfg->size; 28945f379342SAlexander V. Chernikov tinfo->count4 = cfg->items; 28955f379342SAlexander V. Chernikov tinfo->itemsize4 = sizeof(struct fhashentry4); 28965f379342SAlexander V. Chernikov tinfo->itemsize6 = sizeof(struct fhashentry6); 28975f379342SAlexander V. Chernikov } 28985f379342SAlexander V. Chernikov 2899914bffb6SAlexander V. Chernikov static int 2900914bffb6SAlexander V. Chernikov ta_dump_fhash_tentry(void *ta_state, struct table_info *ti, void *e, 2901914bffb6SAlexander V. Chernikov ipfw_obj_tentry *tent) 2902914bffb6SAlexander V. Chernikov { 2903914bffb6SAlexander V. Chernikov struct fhash_cfg *cfg; 2904914bffb6SAlexander V. Chernikov struct fhashentry *ent; 2905914bffb6SAlexander V. Chernikov struct fhashentry4 *fe4; 2906914bffb6SAlexander V. Chernikov struct fhashentry6 *fe6; 2907914bffb6SAlexander V. Chernikov struct tflow_entry *tfe; 2908914bffb6SAlexander V. Chernikov 2909914bffb6SAlexander V. Chernikov cfg = (struct fhash_cfg *)ta_state; 2910914bffb6SAlexander V. Chernikov ent = (struct fhashentry *)e; 2911914bffb6SAlexander V. Chernikov tfe = &tent->k.flow; 2912914bffb6SAlexander V. Chernikov 2913914bffb6SAlexander V. Chernikov tfe->af = ent->af; 2914914bffb6SAlexander V. Chernikov tfe->proto = ent->proto; 2915914bffb6SAlexander V. Chernikov tfe->dport = htons(ent->dport); 2916914bffb6SAlexander V. Chernikov tfe->sport = htons(ent->sport); 2917914bffb6SAlexander V. Chernikov tent->value = ent->value; 2918914bffb6SAlexander V. Chernikov tent->subtype = ent->af; 2919914bffb6SAlexander V. Chernikov 2920914bffb6SAlexander V. Chernikov if (ent->af == AF_INET) { 2921914bffb6SAlexander V. Chernikov fe4 = (struct fhashentry4 *)ent; 2922914bffb6SAlexander V. Chernikov tfe->a.a4.sip.s_addr = htonl(fe4->sip.s_addr); 2923914bffb6SAlexander V. Chernikov tfe->a.a4.dip.s_addr = htonl(fe4->dip.s_addr); 2924914bffb6SAlexander V. Chernikov tent->masklen = 32; 2925914bffb6SAlexander V. Chernikov #ifdef INET6 2926914bffb6SAlexander V. Chernikov } else { 2927914bffb6SAlexander V. Chernikov fe6 = (struct fhashentry6 *)ent; 2928914bffb6SAlexander V. Chernikov tfe->a.a6.sip6 = fe6->sip6; 2929914bffb6SAlexander V. Chernikov tfe->a.a6.dip6 = fe6->dip6; 2930914bffb6SAlexander V. Chernikov tent->masklen = 128; 2931914bffb6SAlexander V. Chernikov #endif 2932914bffb6SAlexander V. Chernikov } 2933914bffb6SAlexander V. Chernikov 2934914bffb6SAlexander V. Chernikov return (0); 2935914bffb6SAlexander V. Chernikov } 2936914bffb6SAlexander V. Chernikov 2937914bffb6SAlexander V. Chernikov static int 2938914bffb6SAlexander V. Chernikov tei_to_fhash_ent(struct tentry_info *tei, struct fhashentry *ent) 2939914bffb6SAlexander V. Chernikov { 2940914bffb6SAlexander V. Chernikov struct fhashentry4 *fe4; 2941914bffb6SAlexander V. Chernikov struct fhashentry6 *fe6; 2942914bffb6SAlexander V. Chernikov struct tflow_entry *tfe; 2943914bffb6SAlexander V. Chernikov 2944914bffb6SAlexander V. Chernikov tfe = (struct tflow_entry *)tei->paddr; 2945914bffb6SAlexander V. Chernikov 2946914bffb6SAlexander V. Chernikov ent->af = tei->subtype; 2947914bffb6SAlexander V. Chernikov ent->proto = tfe->proto; 2948914bffb6SAlexander V. Chernikov ent->value = tei->value; 2949914bffb6SAlexander V. Chernikov ent->dport = ntohs(tfe->dport); 2950914bffb6SAlexander V. Chernikov ent->sport = ntohs(tfe->sport); 2951914bffb6SAlexander V. Chernikov 2952914bffb6SAlexander V. Chernikov if (tei->subtype == AF_INET) { 2953914bffb6SAlexander V. Chernikov #ifdef INET 2954914bffb6SAlexander V. Chernikov fe4 = (struct fhashentry4 *)ent; 2955914bffb6SAlexander V. Chernikov fe4->sip.s_addr = ntohl(tfe->a.a4.sip.s_addr); 2956914bffb6SAlexander V. Chernikov fe4->dip.s_addr = ntohl(tfe->a.a4.dip.s_addr); 2957914bffb6SAlexander V. Chernikov #endif 2958914bffb6SAlexander V. Chernikov #ifdef INET6 2959914bffb6SAlexander V. Chernikov } else if (tei->subtype == AF_INET6) { 2960914bffb6SAlexander V. Chernikov fe6 = (struct fhashentry6 *)ent; 2961914bffb6SAlexander V. Chernikov fe6->sip6 = tfe->a.a6.sip6; 2962914bffb6SAlexander V. Chernikov fe6->dip6 = tfe->a.a6.dip6; 2963914bffb6SAlexander V. Chernikov #endif 2964914bffb6SAlexander V. Chernikov } else { 2965914bffb6SAlexander V. Chernikov /* Unknown CIDR type */ 2966914bffb6SAlexander V. Chernikov return (EINVAL); 2967914bffb6SAlexander V. Chernikov } 2968914bffb6SAlexander V. Chernikov 2969914bffb6SAlexander V. Chernikov return (0); 2970914bffb6SAlexander V. Chernikov } 2971914bffb6SAlexander V. Chernikov 2972914bffb6SAlexander V. Chernikov 2973914bffb6SAlexander V. Chernikov static int 2974914bffb6SAlexander V. Chernikov ta_find_fhash_tentry(void *ta_state, struct table_info *ti, 2975914bffb6SAlexander V. Chernikov ipfw_obj_tentry *tent) 2976914bffb6SAlexander V. Chernikov { 2977914bffb6SAlexander V. Chernikov struct fhash_cfg *cfg; 2978914bffb6SAlexander V. Chernikov struct fhashbhead *head; 2979914bffb6SAlexander V. Chernikov struct fhashentry *ent, *tmp; 2980914bffb6SAlexander V. Chernikov struct fhashentry6 fe6; 2981914bffb6SAlexander V. Chernikov struct tentry_info tei; 2982914bffb6SAlexander V. Chernikov int error; 2983914bffb6SAlexander V. Chernikov uint32_t hash; 2984914bffb6SAlexander V. Chernikov size_t sz; 2985914bffb6SAlexander V. Chernikov 2986914bffb6SAlexander V. Chernikov cfg = (struct fhash_cfg *)ta_state; 2987914bffb6SAlexander V. Chernikov 2988914bffb6SAlexander V. Chernikov ent = &fe6.e; 2989914bffb6SAlexander V. Chernikov 2990914bffb6SAlexander V. Chernikov memset(&fe6, 0, sizeof(fe6)); 2991914bffb6SAlexander V. Chernikov memset(&tei, 0, sizeof(tei)); 2992914bffb6SAlexander V. Chernikov 2993914bffb6SAlexander V. Chernikov tei.paddr = &tent->k.flow; 2994914bffb6SAlexander V. Chernikov tei.subtype = tent->subtype; 2995914bffb6SAlexander V. Chernikov 2996914bffb6SAlexander V. Chernikov if ((error = tei_to_fhash_ent(&tei, ent)) != 0) 2997914bffb6SAlexander V. Chernikov return (error); 2998914bffb6SAlexander V. Chernikov 2999914bffb6SAlexander V. Chernikov head = cfg->head; 3000914bffb6SAlexander V. Chernikov hash = hash_flow_ent(ent, cfg->size); 3001914bffb6SAlexander V. Chernikov 3002914bffb6SAlexander V. Chernikov if (tei.subtype == AF_INET) 3003914bffb6SAlexander V. Chernikov sz = 2 * sizeof(struct in_addr); 3004914bffb6SAlexander V. Chernikov else 3005914bffb6SAlexander V. Chernikov sz = 2 * sizeof(struct in6_addr); 3006914bffb6SAlexander V. Chernikov 3007914bffb6SAlexander V. Chernikov /* Check for existence */ 3008914bffb6SAlexander V. Chernikov SLIST_FOREACH(tmp, &head[hash], next) { 3009914bffb6SAlexander V. Chernikov if (cmp_flow_ent(tmp, ent, sz) != 0) { 3010914bffb6SAlexander V. Chernikov ta_dump_fhash_tentry(ta_state, ti, tmp, tent); 3011914bffb6SAlexander V. Chernikov return (0); 3012914bffb6SAlexander V. Chernikov } 3013914bffb6SAlexander V. Chernikov } 3014914bffb6SAlexander V. Chernikov 3015914bffb6SAlexander V. Chernikov return (ENOENT); 3016914bffb6SAlexander V. Chernikov } 3017914bffb6SAlexander V. Chernikov 3018914bffb6SAlexander V. Chernikov static void 3019914bffb6SAlexander V. Chernikov ta_foreach_fhash(void *ta_state, struct table_info *ti, ta_foreach_f *f, 3020914bffb6SAlexander V. Chernikov void *arg) 3021914bffb6SAlexander V. Chernikov { 3022914bffb6SAlexander V. Chernikov struct fhash_cfg *cfg; 3023914bffb6SAlexander V. Chernikov struct fhashentry *ent, *ent_next; 3024914bffb6SAlexander V. Chernikov int i; 3025914bffb6SAlexander V. Chernikov 3026914bffb6SAlexander V. Chernikov cfg = (struct fhash_cfg *)ta_state; 3027914bffb6SAlexander V. Chernikov 3028914bffb6SAlexander V. Chernikov for (i = 0; i < cfg->size; i++) 3029914bffb6SAlexander V. Chernikov SLIST_FOREACH_SAFE(ent, &cfg->head[i], next, ent_next) 3030914bffb6SAlexander V. Chernikov f(ent, arg); 3031914bffb6SAlexander V. Chernikov } 3032914bffb6SAlexander V. Chernikov 3033914bffb6SAlexander V. Chernikov static int 3034914bffb6SAlexander V. Chernikov ta_prepare_add_fhash(struct ip_fw_chain *ch, struct tentry_info *tei, 3035914bffb6SAlexander V. Chernikov void *ta_buf) 3036914bffb6SAlexander V. Chernikov { 3037914bffb6SAlexander V. Chernikov struct ta_buf_fhash *tb; 3038914bffb6SAlexander V. Chernikov struct fhashentry *ent; 3039914bffb6SAlexander V. Chernikov size_t sz; 3040914bffb6SAlexander V. Chernikov int error; 3041914bffb6SAlexander V. Chernikov 3042914bffb6SAlexander V. Chernikov tb = (struct ta_buf_fhash *)ta_buf; 3043914bffb6SAlexander V. Chernikov 3044914bffb6SAlexander V. Chernikov if (tei->subtype == AF_INET) 3045914bffb6SAlexander V. Chernikov sz = sizeof(struct fhashentry4); 3046914bffb6SAlexander V. Chernikov else if (tei->subtype == AF_INET6) 3047914bffb6SAlexander V. Chernikov sz = sizeof(struct fhashentry6); 3048914bffb6SAlexander V. Chernikov else 3049914bffb6SAlexander V. Chernikov return (EINVAL); 3050914bffb6SAlexander V. Chernikov 3051914bffb6SAlexander V. Chernikov ent = malloc(sz, M_IPFW_TBL, M_WAITOK | M_ZERO); 3052914bffb6SAlexander V. Chernikov 3053914bffb6SAlexander V. Chernikov error = tei_to_fhash_ent(tei, ent); 3054914bffb6SAlexander V. Chernikov if (error != 0) { 3055914bffb6SAlexander V. Chernikov free(ent, M_IPFW_TBL); 3056914bffb6SAlexander V. Chernikov return (error); 3057914bffb6SAlexander V. Chernikov } 3058914bffb6SAlexander V. Chernikov tb->ent_ptr = ent; 3059914bffb6SAlexander V. Chernikov 3060914bffb6SAlexander V. Chernikov return (0); 3061914bffb6SAlexander V. Chernikov } 3062914bffb6SAlexander V. Chernikov 3063914bffb6SAlexander V. Chernikov static int 3064914bffb6SAlexander V. Chernikov ta_add_fhash(void *ta_state, struct table_info *ti, struct tentry_info *tei, 3065b6ee846eSAlexander V. Chernikov void *ta_buf, uint32_t *pnum) 3066914bffb6SAlexander V. Chernikov { 3067914bffb6SAlexander V. Chernikov struct fhash_cfg *cfg; 3068914bffb6SAlexander V. Chernikov struct fhashbhead *head; 3069914bffb6SAlexander V. Chernikov struct fhashentry *ent, *tmp; 3070914bffb6SAlexander V. Chernikov struct ta_buf_fhash *tb; 3071914bffb6SAlexander V. Chernikov int exists; 3072648e8380SAlexander V. Chernikov uint32_t hash, value; 3073914bffb6SAlexander V. Chernikov size_t sz; 3074914bffb6SAlexander V. Chernikov 3075914bffb6SAlexander V. Chernikov cfg = (struct fhash_cfg *)ta_state; 3076914bffb6SAlexander V. Chernikov tb = (struct ta_buf_fhash *)ta_buf; 3077914bffb6SAlexander V. Chernikov ent = (struct fhashentry *)tb->ent_ptr; 3078914bffb6SAlexander V. Chernikov exists = 0; 3079914bffb6SAlexander V. Chernikov 3080914bffb6SAlexander V. Chernikov head = cfg->head; 3081914bffb6SAlexander V. Chernikov hash = hash_flow_ent(ent, cfg->size); 3082914bffb6SAlexander V. Chernikov 3083914bffb6SAlexander V. Chernikov if (tei->subtype == AF_INET) 3084914bffb6SAlexander V. Chernikov sz = 2 * sizeof(struct in_addr); 3085914bffb6SAlexander V. Chernikov else 3086914bffb6SAlexander V. Chernikov sz = 2 * sizeof(struct in6_addr); 3087914bffb6SAlexander V. Chernikov 3088914bffb6SAlexander V. Chernikov /* Check for existence */ 3089914bffb6SAlexander V. Chernikov SLIST_FOREACH(tmp, &head[hash], next) { 3090914bffb6SAlexander V. Chernikov if (cmp_flow_ent(tmp, ent, sz) != 0) { 3091914bffb6SAlexander V. Chernikov exists = 1; 3092914bffb6SAlexander V. Chernikov break; 3093914bffb6SAlexander V. Chernikov } 3094914bffb6SAlexander V. Chernikov } 3095914bffb6SAlexander V. Chernikov 3096914bffb6SAlexander V. Chernikov if (exists == 1) { 3097914bffb6SAlexander V. Chernikov if ((tei->flags & TEI_FLAGS_UPDATE) == 0) 3098914bffb6SAlexander V. Chernikov return (EEXIST); 3099914bffb6SAlexander V. Chernikov /* Record already exists. Update value if we're asked to */ 3100648e8380SAlexander V. Chernikov /* Exchange values between tmp and @tei */ 3101648e8380SAlexander V. Chernikov value = tmp->value; 3102914bffb6SAlexander V. Chernikov tmp->value = tei->value; 3103648e8380SAlexander V. Chernikov tei->value = value; 3104914bffb6SAlexander V. Chernikov /* Indicate that update has happened instead of addition */ 3105914bffb6SAlexander V. Chernikov tei->flags |= TEI_FLAGS_UPDATED; 3106914bffb6SAlexander V. Chernikov *pnum = 0; 3107914bffb6SAlexander V. Chernikov } else { 31084c0c07a5SAlexander V. Chernikov if ((tei->flags & TEI_FLAGS_DONTADD) != 0) 31094c0c07a5SAlexander V. Chernikov return (EFBIG); 31104c0c07a5SAlexander V. Chernikov 3111914bffb6SAlexander V. Chernikov SLIST_INSERT_HEAD(&head[hash], ent, next); 3112914bffb6SAlexander V. Chernikov tb->ent_ptr = NULL; 3113914bffb6SAlexander V. Chernikov *pnum = 1; 3114914bffb6SAlexander V. Chernikov 3115914bffb6SAlexander V. Chernikov /* Update counters and check if we need to grow hash */ 3116914bffb6SAlexander V. Chernikov cfg->items++; 3117914bffb6SAlexander V. Chernikov } 3118914bffb6SAlexander V. Chernikov 3119914bffb6SAlexander V. Chernikov return (0); 3120914bffb6SAlexander V. Chernikov } 3121914bffb6SAlexander V. Chernikov 3122914bffb6SAlexander V. Chernikov static int 3123914bffb6SAlexander V. Chernikov ta_prepare_del_fhash(struct ip_fw_chain *ch, struct tentry_info *tei, 3124914bffb6SAlexander V. Chernikov void *ta_buf) 3125914bffb6SAlexander V. Chernikov { 3126914bffb6SAlexander V. Chernikov struct ta_buf_fhash *tb; 3127914bffb6SAlexander V. Chernikov 3128914bffb6SAlexander V. Chernikov tb = (struct ta_buf_fhash *)ta_buf; 3129914bffb6SAlexander V. Chernikov 3130914bffb6SAlexander V. Chernikov return (tei_to_fhash_ent(tei, &tb->fe6.e)); 3131914bffb6SAlexander V. Chernikov } 3132914bffb6SAlexander V. Chernikov 3133914bffb6SAlexander V. Chernikov static int 3134914bffb6SAlexander V. Chernikov ta_del_fhash(void *ta_state, struct table_info *ti, struct tentry_info *tei, 3135b6ee846eSAlexander V. Chernikov void *ta_buf, uint32_t *pnum) 3136914bffb6SAlexander V. Chernikov { 3137914bffb6SAlexander V. Chernikov struct fhash_cfg *cfg; 3138914bffb6SAlexander V. Chernikov struct fhashbhead *head; 3139914bffb6SAlexander V. Chernikov struct fhashentry *ent, *tmp; 3140914bffb6SAlexander V. Chernikov struct ta_buf_fhash *tb; 3141914bffb6SAlexander V. Chernikov uint32_t hash; 3142914bffb6SAlexander V. Chernikov size_t sz; 3143914bffb6SAlexander V. Chernikov 3144914bffb6SAlexander V. Chernikov cfg = (struct fhash_cfg *)ta_state; 3145914bffb6SAlexander V. Chernikov tb = (struct ta_buf_fhash *)ta_buf; 3146914bffb6SAlexander V. Chernikov ent = &tb->fe6.e; 3147914bffb6SAlexander V. Chernikov 3148914bffb6SAlexander V. Chernikov head = cfg->head; 3149914bffb6SAlexander V. Chernikov hash = hash_flow_ent(ent, cfg->size); 3150914bffb6SAlexander V. Chernikov 3151914bffb6SAlexander V. Chernikov if (tei->subtype == AF_INET) 3152914bffb6SAlexander V. Chernikov sz = 2 * sizeof(struct in_addr); 3153914bffb6SAlexander V. Chernikov else 3154914bffb6SAlexander V. Chernikov sz = 2 * sizeof(struct in6_addr); 3155914bffb6SAlexander V. Chernikov 3156914bffb6SAlexander V. Chernikov /* Check for existence */ 3157914bffb6SAlexander V. Chernikov SLIST_FOREACH(tmp, &head[hash], next) { 3158648e8380SAlexander V. Chernikov if (cmp_flow_ent(tmp, ent, sz) == 0) 3159648e8380SAlexander V. Chernikov continue; 3160648e8380SAlexander V. Chernikov 3161914bffb6SAlexander V. Chernikov SLIST_REMOVE(&head[hash], tmp, fhashentry, next); 3162648e8380SAlexander V. Chernikov tei->value = tmp->value; 3163914bffb6SAlexander V. Chernikov *pnum = 1; 3164914bffb6SAlexander V. Chernikov cfg->items--; 3165648e8380SAlexander V. Chernikov tb->ent_ptr = tmp; 3166914bffb6SAlexander V. Chernikov return (0); 3167914bffb6SAlexander V. Chernikov } 3168914bffb6SAlexander V. Chernikov 3169914bffb6SAlexander V. Chernikov return (ENOENT); 3170914bffb6SAlexander V. Chernikov } 3171914bffb6SAlexander V. Chernikov 3172914bffb6SAlexander V. Chernikov static void 3173914bffb6SAlexander V. Chernikov ta_flush_fhash_entry(struct ip_fw_chain *ch, struct tentry_info *tei, 3174914bffb6SAlexander V. Chernikov void *ta_buf) 3175914bffb6SAlexander V. Chernikov { 3176914bffb6SAlexander V. Chernikov struct ta_buf_fhash *tb; 3177914bffb6SAlexander V. Chernikov 3178914bffb6SAlexander V. Chernikov tb = (struct ta_buf_fhash *)ta_buf; 3179914bffb6SAlexander V. Chernikov 3180914bffb6SAlexander V. Chernikov if (tb->ent_ptr != NULL) 3181914bffb6SAlexander V. Chernikov free(tb->ent_ptr, M_IPFW_TBL); 3182914bffb6SAlexander V. Chernikov } 3183914bffb6SAlexander V. Chernikov 3184914bffb6SAlexander V. Chernikov /* 3185914bffb6SAlexander V. Chernikov * Hash growing callbacks. 3186914bffb6SAlexander V. Chernikov */ 3187914bffb6SAlexander V. Chernikov 3188b6ee846eSAlexander V. Chernikov static int 3189b6ee846eSAlexander V. Chernikov ta_has_space_fhash(void *ta_state, struct table_info *ti, uint32_t count, 3190b6ee846eSAlexander V. Chernikov uint64_t *pflags) 3191b6ee846eSAlexander V. Chernikov { 3192b6ee846eSAlexander V. Chernikov struct fhash_cfg *cfg; 3193b6ee846eSAlexander V. Chernikov 3194b6ee846eSAlexander V. Chernikov cfg = (struct fhash_cfg *)ta_state; 3195b6ee846eSAlexander V. Chernikov 3196b6ee846eSAlexander V. Chernikov if (cfg->items > cfg->size && cfg->size < 65536) { 3197b6ee846eSAlexander V. Chernikov *pflags = cfg->size * 2; 3198b6ee846eSAlexander V. Chernikov return (0); 3199b6ee846eSAlexander V. Chernikov } 3200b6ee846eSAlexander V. Chernikov 3201b6ee846eSAlexander V. Chernikov return (1); 3202b6ee846eSAlexander V. Chernikov } 3203b6ee846eSAlexander V. Chernikov 3204914bffb6SAlexander V. Chernikov /* 3205914bffb6SAlexander V. Chernikov * Allocate new, larger fhash. 3206914bffb6SAlexander V. Chernikov */ 3207914bffb6SAlexander V. Chernikov static int 3208914bffb6SAlexander V. Chernikov ta_prepare_mod_fhash(void *ta_buf, uint64_t *pflags) 3209914bffb6SAlexander V. Chernikov { 3210914bffb6SAlexander V. Chernikov struct mod_item *mi; 3211914bffb6SAlexander V. Chernikov struct fhashbhead *head; 3212914bffb6SAlexander V. Chernikov int i; 3213914bffb6SAlexander V. Chernikov 3214914bffb6SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 3215914bffb6SAlexander V. Chernikov 3216914bffb6SAlexander V. Chernikov memset(mi, 0, sizeof(struct mod_item)); 3217914bffb6SAlexander V. Chernikov mi->size = *pflags; 3218914bffb6SAlexander V. Chernikov head = malloc(sizeof(struct fhashbhead) * mi->size, M_IPFW, 3219914bffb6SAlexander V. Chernikov M_WAITOK | M_ZERO); 3220914bffb6SAlexander V. Chernikov for (i = 0; i < mi->size; i++) 3221914bffb6SAlexander V. Chernikov SLIST_INIT(&head[i]); 3222914bffb6SAlexander V. Chernikov 3223914bffb6SAlexander V. Chernikov mi->main_ptr = head; 3224914bffb6SAlexander V. Chernikov 3225914bffb6SAlexander V. Chernikov return (0); 3226914bffb6SAlexander V. Chernikov } 3227914bffb6SAlexander V. Chernikov 3228914bffb6SAlexander V. Chernikov /* 3229914bffb6SAlexander V. Chernikov * Copy data from old runtime array to new one. 3230914bffb6SAlexander V. Chernikov */ 3231914bffb6SAlexander V. Chernikov static int 3232914bffb6SAlexander V. Chernikov ta_fill_mod_fhash(void *ta_state, struct table_info *ti, void *ta_buf, 3233914bffb6SAlexander V. Chernikov uint64_t *pflags) 3234914bffb6SAlexander V. Chernikov { 3235914bffb6SAlexander V. Chernikov 3236914bffb6SAlexander V. Chernikov /* In is not possible to do rehash if we're not holidng WLOCK. */ 3237914bffb6SAlexander V. Chernikov return (0); 3238914bffb6SAlexander V. Chernikov } 3239914bffb6SAlexander V. Chernikov 3240914bffb6SAlexander V. Chernikov /* 3241914bffb6SAlexander V. Chernikov * Switch old & new arrays. 3242914bffb6SAlexander V. Chernikov */ 3243914bffb6SAlexander V. Chernikov static int 3244914bffb6SAlexander V. Chernikov ta_modify_fhash(void *ta_state, struct table_info *ti, void *ta_buf, 3245914bffb6SAlexander V. Chernikov uint64_t pflags) 3246914bffb6SAlexander V. Chernikov { 3247914bffb6SAlexander V. Chernikov struct mod_item *mi; 3248914bffb6SAlexander V. Chernikov struct fhash_cfg *cfg; 3249914bffb6SAlexander V. Chernikov struct fhashbhead *old_head, *new_head; 3250914bffb6SAlexander V. Chernikov struct fhashentry *ent, *ent_next; 3251914bffb6SAlexander V. Chernikov int i; 3252914bffb6SAlexander V. Chernikov uint32_t nhash; 3253914bffb6SAlexander V. Chernikov size_t old_size; 3254914bffb6SAlexander V. Chernikov 3255914bffb6SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 3256914bffb6SAlexander V. Chernikov cfg = (struct fhash_cfg *)ta_state; 3257914bffb6SAlexander V. Chernikov 3258914bffb6SAlexander V. Chernikov /* Check which hash we need to grow and do we still need that */ 3259914bffb6SAlexander V. Chernikov old_size = cfg->size; 3260914bffb6SAlexander V. Chernikov old_head = ti->state; 3261914bffb6SAlexander V. Chernikov 3262914bffb6SAlexander V. Chernikov if (old_size >= mi->size) 3263914bffb6SAlexander V. Chernikov return (0); 3264914bffb6SAlexander V. Chernikov 3265914bffb6SAlexander V. Chernikov new_head = (struct fhashbhead *)mi->main_ptr; 3266914bffb6SAlexander V. Chernikov for (i = 0; i < old_size; i++) { 3267914bffb6SAlexander V. Chernikov SLIST_FOREACH_SAFE(ent, &old_head[i], next, ent_next) { 3268914bffb6SAlexander V. Chernikov nhash = hash_flow_ent(ent, mi->size); 3269914bffb6SAlexander V. Chernikov SLIST_INSERT_HEAD(&new_head[nhash], ent, next); 3270914bffb6SAlexander V. Chernikov } 3271914bffb6SAlexander V. Chernikov } 3272914bffb6SAlexander V. Chernikov 3273914bffb6SAlexander V. Chernikov ti->state = new_head; 3274914bffb6SAlexander V. Chernikov ti->data = mi->size; 3275914bffb6SAlexander V. Chernikov cfg->head = new_head; 3276914bffb6SAlexander V. Chernikov cfg->size = mi->size; 3277914bffb6SAlexander V. Chernikov 3278914bffb6SAlexander V. Chernikov mi->main_ptr = old_head; 3279914bffb6SAlexander V. Chernikov 3280914bffb6SAlexander V. Chernikov return (0); 3281914bffb6SAlexander V. Chernikov } 3282914bffb6SAlexander V. Chernikov 3283914bffb6SAlexander V. Chernikov /* 3284914bffb6SAlexander V. Chernikov * Free unneded array. 3285914bffb6SAlexander V. Chernikov */ 3286914bffb6SAlexander V. Chernikov static void 3287914bffb6SAlexander V. Chernikov ta_flush_mod_fhash(void *ta_buf) 3288914bffb6SAlexander V. Chernikov { 3289914bffb6SAlexander V. Chernikov struct mod_item *mi; 3290914bffb6SAlexander V. Chernikov 3291914bffb6SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 3292914bffb6SAlexander V. Chernikov if (mi->main_ptr != NULL) 3293914bffb6SAlexander V. Chernikov free(mi->main_ptr, M_IPFW); 3294914bffb6SAlexander V. Chernikov } 3295914bffb6SAlexander V. Chernikov 3296914bffb6SAlexander V. Chernikov struct table_algo flow_hash = { 3297914bffb6SAlexander V. Chernikov .name = "flow:hash", 3298914bffb6SAlexander V. Chernikov .type = IPFW_TABLE_FLOW, 329957a1cf95SAlexander V. Chernikov .flags = TA_FLAG_DEFAULT, 330057a1cf95SAlexander V. Chernikov .ta_buf_size = sizeof(struct ta_buf_fhash), 3301914bffb6SAlexander V. Chernikov .init = ta_init_fhash, 3302914bffb6SAlexander V. Chernikov .destroy = ta_destroy_fhash, 3303914bffb6SAlexander V. Chernikov .prepare_add = ta_prepare_add_fhash, 3304914bffb6SAlexander V. Chernikov .prepare_del = ta_prepare_del_fhash, 3305914bffb6SAlexander V. Chernikov .add = ta_add_fhash, 3306914bffb6SAlexander V. Chernikov .del = ta_del_fhash, 3307914bffb6SAlexander V. Chernikov .flush_entry = ta_flush_fhash_entry, 3308914bffb6SAlexander V. Chernikov .foreach = ta_foreach_fhash, 3309914bffb6SAlexander V. Chernikov .dump_tentry = ta_dump_fhash_tentry, 3310914bffb6SAlexander V. Chernikov .find_tentry = ta_find_fhash_tentry, 33115f379342SAlexander V. Chernikov .dump_tinfo = ta_dump_fhash_tinfo, 3312b6ee846eSAlexander V. Chernikov .has_space = ta_has_space_fhash, 3313914bffb6SAlexander V. Chernikov .prepare_mod = ta_prepare_mod_fhash, 3314914bffb6SAlexander V. Chernikov .fill_mod = ta_fill_mod_fhash, 3315914bffb6SAlexander V. Chernikov .modify = ta_modify_fhash, 3316914bffb6SAlexander V. Chernikov .flush_mod = ta_flush_mod_fhash, 3317914bffb6SAlexander V. Chernikov }; 33183fe2ef91SAlexander V. Chernikov 33199f7d47b0SAlexander V. Chernikov void 33200b565ac0SAlexander V. Chernikov ipfw_table_algo_init(struct ip_fw_chain *ch) 33219f7d47b0SAlexander V. Chernikov { 33220b565ac0SAlexander V. Chernikov size_t sz; 33230b565ac0SAlexander V. Chernikov 33249f7d47b0SAlexander V. Chernikov /* 33259f7d47b0SAlexander V. Chernikov * Register all algorithms presented here. 33269f7d47b0SAlexander V. Chernikov */ 33270b565ac0SAlexander V. Chernikov sz = sizeof(struct table_algo); 33280b565ac0SAlexander V. Chernikov ipfw_add_table_algo(ch, &cidr_radix, sz, &cidr_radix.idx); 33290b565ac0SAlexander V. Chernikov ipfw_add_table_algo(ch, &cidr_hash, sz, &cidr_hash.idx); 33300b565ac0SAlexander V. Chernikov ipfw_add_table_algo(ch, &iface_idx, sz, &iface_idx.idx); 3331b23d5de9SAlexander V. Chernikov ipfw_add_table_algo(ch, &number_array, sz, &number_array.idx); 3332914bffb6SAlexander V. Chernikov ipfw_add_table_algo(ch, &flow_hash, sz, &flow_hash.idx); 33339f7d47b0SAlexander V. Chernikov } 33349f7d47b0SAlexander V. Chernikov 33359f7d47b0SAlexander V. Chernikov void 33360b565ac0SAlexander V. Chernikov ipfw_table_algo_destroy(struct ip_fw_chain *ch) 33379f7d47b0SAlexander V. Chernikov { 33380b565ac0SAlexander V. Chernikov 33390b565ac0SAlexander V. Chernikov ipfw_del_table_algo(ch, cidr_radix.idx); 33400b565ac0SAlexander V. Chernikov ipfw_del_table_algo(ch, cidr_hash.idx); 33410b565ac0SAlexander V. Chernikov ipfw_del_table_algo(ch, iface_idx.idx); 3342b23d5de9SAlexander V. Chernikov ipfw_del_table_algo(ch, number_array.idx); 3343914bffb6SAlexander V. Chernikov ipfw_del_table_algo(ch, flow_hash.idx); 33449f7d47b0SAlexander V. Chernikov } 33459f7d47b0SAlexander V. Chernikov 33469f7d47b0SAlexander V. Chernikov 3347