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 1230bce0c23SAlexander V. Chernikov struct ta_buf_cidr 1240bce0c23SAlexander V. Chernikov { 1250bce0c23SAlexander V. Chernikov void *ent_ptr; 1260bce0c23SAlexander V. Chernikov struct sockaddr *addr_ptr; 1270bce0c23SAlexander V. Chernikov struct sockaddr *mask_ptr; 1280bce0c23SAlexander V. Chernikov union { 1290bce0c23SAlexander V. Chernikov struct { 1300bce0c23SAlexander V. Chernikov struct sockaddr_in sa; 1310bce0c23SAlexander V. Chernikov struct sockaddr_in ma; 1320bce0c23SAlexander V. Chernikov } a4; 1330bce0c23SAlexander V. Chernikov struct { 1340bce0c23SAlexander V. Chernikov struct sa_in6 sa; 1350bce0c23SAlexander V. Chernikov struct sa_in6 ma; 1360bce0c23SAlexander V. Chernikov } a6; 1370bce0c23SAlexander V. Chernikov } addr; 1380bce0c23SAlexander V. Chernikov }; 1390bce0c23SAlexander V. Chernikov 1409f7d47b0SAlexander V. Chernikov static int 1419f7d47b0SAlexander V. Chernikov ta_lookup_radix(struct table_info *ti, void *key, uint32_t keylen, 1429f7d47b0SAlexander V. Chernikov uint32_t *val) 1439f7d47b0SAlexander V. Chernikov { 1449f7d47b0SAlexander V. Chernikov struct radix_node_head *rnh; 1459f7d47b0SAlexander V. Chernikov 1469f7d47b0SAlexander V. Chernikov if (keylen == sizeof(in_addr_t)) { 147e0a8b9eeSAlexander V. Chernikov struct radix_cidr_entry *ent; 1489f7d47b0SAlexander V. Chernikov struct sockaddr_in sa; 1499f7d47b0SAlexander V. Chernikov KEY_LEN(sa) = KEY_LEN_INET; 1509f7d47b0SAlexander V. Chernikov sa.sin_addr.s_addr = *((in_addr_t *)key); 1519f7d47b0SAlexander V. Chernikov rnh = (struct radix_node_head *)ti->state; 152e0a8b9eeSAlexander V. Chernikov ent = (struct radix_cidr_entry *)(rnh->rnh_matchaddr(&sa, rnh)); 1539f7d47b0SAlexander V. Chernikov if (ent != NULL) { 1549f7d47b0SAlexander V. Chernikov *val = ent->value; 1559f7d47b0SAlexander V. Chernikov return (1); 1569f7d47b0SAlexander V. Chernikov } 1579f7d47b0SAlexander V. Chernikov } else { 158e0a8b9eeSAlexander V. Chernikov struct radix_cidr_xentry *xent; 159e0a8b9eeSAlexander V. Chernikov struct sa_in6 sa6; 1609f7d47b0SAlexander V. Chernikov KEY_LEN(sa6) = KEY_LEN_INET6; 1619f7d47b0SAlexander V. Chernikov memcpy(&sa6.sin6_addr, key, sizeof(struct in6_addr)); 1629f7d47b0SAlexander V. Chernikov rnh = (struct radix_node_head *)ti->xstate; 163e0a8b9eeSAlexander V. Chernikov xent = (struct radix_cidr_xentry *)(rnh->rnh_matchaddr(&sa6, rnh)); 1649f7d47b0SAlexander V. Chernikov if (xent != NULL) { 1659f7d47b0SAlexander V. Chernikov *val = xent->value; 1669f7d47b0SAlexander V. Chernikov return (1); 1679f7d47b0SAlexander V. Chernikov } 1689f7d47b0SAlexander V. Chernikov } 1699f7d47b0SAlexander V. Chernikov 1709f7d47b0SAlexander V. Chernikov return (0); 1719f7d47b0SAlexander V. Chernikov } 1729f7d47b0SAlexander V. Chernikov 1739f7d47b0SAlexander V. Chernikov /* 1749f7d47b0SAlexander V. Chernikov * New table 1759f7d47b0SAlexander V. Chernikov */ 1769f7d47b0SAlexander V. Chernikov static int 17768394ec8SAlexander V. Chernikov ta_init_radix(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti, 178914bffb6SAlexander V. Chernikov char *data, uint8_t tflags) 1799f7d47b0SAlexander V. Chernikov { 1809f7d47b0SAlexander V. Chernikov 1819f7d47b0SAlexander V. Chernikov if (!rn_inithead(&ti->state, OFF_LEN_INET)) 1829f7d47b0SAlexander V. Chernikov return (ENOMEM); 1839f7d47b0SAlexander V. Chernikov if (!rn_inithead(&ti->xstate, OFF_LEN_INET6)) { 1849f7d47b0SAlexander V. Chernikov rn_detachhead(&ti->state); 1859f7d47b0SAlexander V. Chernikov return (ENOMEM); 1869f7d47b0SAlexander V. Chernikov } 1879f7d47b0SAlexander V. Chernikov 1889f7d47b0SAlexander V. Chernikov *ta_state = NULL; 1899f7d47b0SAlexander V. Chernikov ti->lookup = ta_lookup_radix; 1909f7d47b0SAlexander V. Chernikov 1919f7d47b0SAlexander V. Chernikov return (0); 1929f7d47b0SAlexander V. Chernikov } 1939f7d47b0SAlexander V. Chernikov 1949f7d47b0SAlexander V. Chernikov static int 195*a399f8beSAlexander V. Chernikov flush_radix_entry(struct radix_node *rn, void *arg) 1969f7d47b0SAlexander V. Chernikov { 1979f7d47b0SAlexander V. Chernikov struct radix_node_head * const rnh = arg; 198e0a8b9eeSAlexander V. Chernikov struct radix_cidr_entry *ent; 1999f7d47b0SAlexander V. Chernikov 200e0a8b9eeSAlexander V. Chernikov ent = (struct radix_cidr_entry *) 2019f7d47b0SAlexander V. Chernikov rnh->rnh_deladdr(rn->rn_key, rn->rn_mask, rnh); 2029f7d47b0SAlexander V. Chernikov if (ent != NULL) 2039f7d47b0SAlexander V. Chernikov free(ent, M_IPFW_TBL); 2049f7d47b0SAlexander V. Chernikov return (0); 2059f7d47b0SAlexander V. Chernikov } 2069f7d47b0SAlexander V. Chernikov 2079f7d47b0SAlexander V. Chernikov static void 2089f7d47b0SAlexander V. Chernikov ta_destroy_radix(void *ta_state, struct table_info *ti) 2099f7d47b0SAlexander V. Chernikov { 2109f7d47b0SAlexander V. Chernikov struct radix_node_head *rnh; 2119f7d47b0SAlexander V. Chernikov 2129f7d47b0SAlexander V. Chernikov rnh = (struct radix_node_head *)(ti->state); 213*a399f8beSAlexander V. Chernikov rnh->rnh_walktree(rnh, flush_radix_entry, rnh); 2149f7d47b0SAlexander V. Chernikov rn_detachhead(&ti->state); 2159f7d47b0SAlexander V. Chernikov 2169f7d47b0SAlexander V. Chernikov rnh = (struct radix_node_head *)(ti->xstate); 217*a399f8beSAlexander V. Chernikov rnh->rnh_walktree(rnh, flush_radix_entry, rnh); 2189f7d47b0SAlexander V. Chernikov rn_detachhead(&ti->xstate); 2199f7d47b0SAlexander V. Chernikov } 2209f7d47b0SAlexander V. Chernikov 2219f7d47b0SAlexander V. Chernikov static int 22281d3153dSAlexander V. Chernikov ta_dump_radix_tentry(void *ta_state, struct table_info *ti, void *e, 22381d3153dSAlexander V. Chernikov ipfw_obj_tentry *tent) 2249f7d47b0SAlexander V. Chernikov { 225e0a8b9eeSAlexander V. Chernikov struct radix_cidr_entry *n; 226e0a8b9eeSAlexander V. Chernikov struct radix_cidr_xentry *xn; 2279f7d47b0SAlexander V. Chernikov 228e0a8b9eeSAlexander V. Chernikov n = (struct radix_cidr_entry *)e; 2299f7d47b0SAlexander V. Chernikov 2309f7d47b0SAlexander V. Chernikov /* Guess IPv4/IPv6 radix by sockaddr family */ 2319f7d47b0SAlexander V. Chernikov if (n->addr.sin_family == AF_INET) { 23281d3153dSAlexander V. Chernikov tent->k.addr.s_addr = n->addr.sin_addr.s_addr; 233e0a8b9eeSAlexander V. Chernikov tent->masklen = n->masklen; 23481d3153dSAlexander V. Chernikov tent->subtype = AF_INET; 23581d3153dSAlexander V. Chernikov tent->value = n->value; 2369f7d47b0SAlexander V. Chernikov #ifdef INET6 2379f7d47b0SAlexander V. Chernikov } else { 238e0a8b9eeSAlexander V. Chernikov xn = (struct radix_cidr_xentry *)e; 239e0a8b9eeSAlexander V. Chernikov memcpy(&tent->k, &xn->addr6.sin6_addr, sizeof(struct in6_addr)); 240e0a8b9eeSAlexander V. Chernikov tent->masklen = xn->masklen; 24181d3153dSAlexander V. Chernikov tent->subtype = AF_INET6; 24281d3153dSAlexander V. Chernikov tent->value = xn->value; 2439f7d47b0SAlexander V. Chernikov #endif 2449f7d47b0SAlexander V. Chernikov } 2459f7d47b0SAlexander V. Chernikov 2469f7d47b0SAlexander V. Chernikov return (0); 2479f7d47b0SAlexander V. Chernikov } 2489f7d47b0SAlexander V. Chernikov 24981d3153dSAlexander V. Chernikov static int 250914bffb6SAlexander V. Chernikov ta_find_radix_tentry(void *ta_state, struct table_info *ti, 251914bffb6SAlexander V. Chernikov ipfw_obj_tentry *tent) 25281d3153dSAlexander V. Chernikov { 25381d3153dSAlexander V. Chernikov struct radix_node_head *rnh; 25481d3153dSAlexander V. Chernikov void *e; 25581d3153dSAlexander V. Chernikov 25681d3153dSAlexander V. Chernikov e = NULL; 257914bffb6SAlexander V. Chernikov if (tent->subtype == AF_INET) { 25881d3153dSAlexander V. Chernikov struct sockaddr_in sa; 25981d3153dSAlexander V. Chernikov KEY_LEN(sa) = KEY_LEN_INET; 260914bffb6SAlexander V. Chernikov sa.sin_addr.s_addr = tent->k.addr.s_addr; 26181d3153dSAlexander V. Chernikov rnh = (struct radix_node_head *)ti->state; 26281d3153dSAlexander V. Chernikov e = rnh->rnh_matchaddr(&sa, rnh); 26381d3153dSAlexander V. Chernikov } else { 264e0a8b9eeSAlexander V. Chernikov struct sa_in6 sa6; 26581d3153dSAlexander V. Chernikov KEY_LEN(sa6) = KEY_LEN_INET6; 266914bffb6SAlexander V. Chernikov memcpy(&sa6.sin6_addr, &tent->k.addr6, sizeof(struct in6_addr)); 26781d3153dSAlexander V. Chernikov rnh = (struct radix_node_head *)ti->xstate; 26881d3153dSAlexander V. Chernikov e = rnh->rnh_matchaddr(&sa6, rnh); 26981d3153dSAlexander V. Chernikov } 27081d3153dSAlexander V. Chernikov 27181d3153dSAlexander V. Chernikov if (e != NULL) { 27281d3153dSAlexander V. Chernikov ta_dump_radix_tentry(ta_state, ti, e, tent); 27381d3153dSAlexander V. Chernikov return (0); 27481d3153dSAlexander V. Chernikov } 27581d3153dSAlexander V. Chernikov 27681d3153dSAlexander V. Chernikov return (ENOENT); 27781d3153dSAlexander V. Chernikov } 27881d3153dSAlexander V. Chernikov 2799f7d47b0SAlexander V. Chernikov static void 2809f7d47b0SAlexander V. Chernikov ta_foreach_radix(void *ta_state, struct table_info *ti, ta_foreach_f *f, 2819f7d47b0SAlexander V. Chernikov void *arg) 2829f7d47b0SAlexander V. Chernikov { 2839f7d47b0SAlexander V. Chernikov struct radix_node_head *rnh; 2849f7d47b0SAlexander V. Chernikov 2859f7d47b0SAlexander V. Chernikov rnh = (struct radix_node_head *)(ti->state); 2869f7d47b0SAlexander V. Chernikov rnh->rnh_walktree(rnh, (walktree_f_t *)f, arg); 2879f7d47b0SAlexander V. Chernikov 2889f7d47b0SAlexander V. Chernikov rnh = (struct radix_node_head *)(ti->xstate); 2899f7d47b0SAlexander V. Chernikov rnh->rnh_walktree(rnh, (walktree_f_t *)f, arg); 2909f7d47b0SAlexander V. Chernikov } 2919f7d47b0SAlexander V. Chernikov 2929f7d47b0SAlexander V. Chernikov 2939f7d47b0SAlexander V. Chernikov #ifdef INET6 2949f7d47b0SAlexander V. Chernikov static inline void 2959f7d47b0SAlexander V. Chernikov ipv6_writemask(struct in6_addr *addr6, uint8_t mask) 2969f7d47b0SAlexander V. Chernikov { 2979f7d47b0SAlexander V. Chernikov uint32_t *cp; 2989f7d47b0SAlexander V. Chernikov 2999f7d47b0SAlexander V. Chernikov for (cp = (uint32_t *)addr6; mask >= 32; mask -= 32) 3009f7d47b0SAlexander V. Chernikov *cp++ = 0xFFFFFFFF; 3019f7d47b0SAlexander V. Chernikov *cp = htonl(mask ? ~((1 << (32 - mask)) - 1) : 0); 3029f7d47b0SAlexander V. Chernikov } 3039f7d47b0SAlexander V. Chernikov #endif 3049f7d47b0SAlexander V. Chernikov 3052e324d29SAlexander V. Chernikov static void 3062e324d29SAlexander V. Chernikov tei_to_sockaddr_ent(struct tentry_info *tei, struct sockaddr *sa, 3072e324d29SAlexander V. Chernikov struct sockaddr *ma, int *set_mask) 3082e324d29SAlexander V. Chernikov { 3092e324d29SAlexander V. Chernikov int mlen; 3102e324d29SAlexander V. Chernikov struct sockaddr_in *addr, *mask; 3112e324d29SAlexander V. Chernikov struct sockaddr_in6 *addr6, *mask6; 3122e324d29SAlexander V. Chernikov in_addr_t a4; 3132e324d29SAlexander V. Chernikov 3142e324d29SAlexander V. Chernikov mlen = tei->masklen; 3152e324d29SAlexander V. Chernikov 3162e324d29SAlexander V. Chernikov if (tei->subtype == AF_INET) { 3172e324d29SAlexander V. Chernikov #ifdef INET 3182e324d29SAlexander V. Chernikov addr = (struct sockaddr_in *)sa; 3192e324d29SAlexander V. Chernikov mask = (struct sockaddr_in *)ma; 3202e324d29SAlexander V. Chernikov /* Set 'total' structure length */ 3212e324d29SAlexander V. Chernikov KEY_LEN(*addr) = KEY_LEN_INET; 3222e324d29SAlexander V. Chernikov KEY_LEN(*mask) = KEY_LEN_INET; 3232e324d29SAlexander V. Chernikov addr->sin_family = AF_INET; 3242e324d29SAlexander V. Chernikov mask->sin_addr.s_addr = 3252e324d29SAlexander V. Chernikov htonl(mlen ? ~((1 << (32 - mlen)) - 1) : 0); 3262e324d29SAlexander V. Chernikov a4 = *((in_addr_t *)tei->paddr); 3272e324d29SAlexander V. Chernikov addr->sin_addr.s_addr = a4 & mask->sin_addr.s_addr; 3282e324d29SAlexander V. Chernikov if (mlen != 32) 3292e324d29SAlexander V. Chernikov *set_mask = 1; 3302e324d29SAlexander V. Chernikov else 3312e324d29SAlexander V. Chernikov *set_mask = 0; 3322e324d29SAlexander V. Chernikov #endif 3332e324d29SAlexander V. Chernikov #ifdef INET6 3342e324d29SAlexander V. Chernikov } else if (tei->subtype == AF_INET6) { 3352e324d29SAlexander V. Chernikov /* IPv6 case */ 3362e324d29SAlexander V. Chernikov addr6 = (struct sockaddr_in6 *)sa; 3372e324d29SAlexander V. Chernikov mask6 = (struct sockaddr_in6 *)ma; 3382e324d29SAlexander V. Chernikov /* Set 'total' structure length */ 3392e324d29SAlexander V. Chernikov KEY_LEN(*addr6) = KEY_LEN_INET6; 3402e324d29SAlexander V. Chernikov KEY_LEN(*mask6) = KEY_LEN_INET6; 3412e324d29SAlexander V. Chernikov addr6->sin6_family = AF_INET6; 3422e324d29SAlexander V. Chernikov ipv6_writemask(&mask6->sin6_addr, mlen); 3432e324d29SAlexander V. Chernikov memcpy(&addr6->sin6_addr, tei->paddr, sizeof(struct in6_addr)); 3442e324d29SAlexander V. Chernikov APPLY_MASK(&addr6->sin6_addr, &mask6->sin6_addr); 3452e324d29SAlexander V. Chernikov if (mlen != 128) 3462e324d29SAlexander V. Chernikov *set_mask = 1; 3472e324d29SAlexander V. Chernikov else 3482e324d29SAlexander V. Chernikov *set_mask = 0; 3492e324d29SAlexander V. Chernikov } 3502e324d29SAlexander V. Chernikov #endif 3512e324d29SAlexander V. Chernikov } 3529f7d47b0SAlexander V. Chernikov 3539f7d47b0SAlexander V. Chernikov static int 354*a399f8beSAlexander V. Chernikov ta_prepare_add_radix(struct ip_fw_chain *ch, struct tentry_info *tei, 35568394ec8SAlexander V. Chernikov void *ta_buf) 3569f7d47b0SAlexander V. Chernikov { 3579f7d47b0SAlexander V. Chernikov struct ta_buf_cidr *tb; 358e0a8b9eeSAlexander V. Chernikov struct radix_cidr_entry *ent; 359e0a8b9eeSAlexander V. Chernikov struct radix_cidr_xentry *xent; 3602e324d29SAlexander V. Chernikov struct sockaddr *addr, *mask; 3612e324d29SAlexander V. Chernikov int mlen, set_mask; 3629f7d47b0SAlexander V. Chernikov 3639f7d47b0SAlexander V. Chernikov tb = (struct ta_buf_cidr *)ta_buf; 3649f7d47b0SAlexander V. Chernikov 3659f7d47b0SAlexander V. Chernikov mlen = tei->masklen; 3662e324d29SAlexander V. Chernikov set_mask = 0; 3679f7d47b0SAlexander V. Chernikov 368ac35ff17SAlexander V. Chernikov if (tei->subtype == AF_INET) { 3699f7d47b0SAlexander V. Chernikov #ifdef INET 3709f7d47b0SAlexander V. Chernikov if (mlen > 32) 3719f7d47b0SAlexander V. Chernikov return (EINVAL); 3729f7d47b0SAlexander V. Chernikov ent = malloc(sizeof(*ent), M_IPFW_TBL, M_WAITOK | M_ZERO); 3739f7d47b0SAlexander V. Chernikov ent->value = tei->value; 374e0a8b9eeSAlexander V. Chernikov ent->masklen = mlen; 3752e324d29SAlexander V. Chernikov 3762e324d29SAlexander V. Chernikov addr = (struct sockaddr *)&ent->addr; 3772e324d29SAlexander V. Chernikov mask = (struct sockaddr *)&tb->addr.a4.ma; 3789f7d47b0SAlexander V. Chernikov tb->ent_ptr = ent; 3799f7d47b0SAlexander V. Chernikov #endif 3809f7d47b0SAlexander V. Chernikov #ifdef INET6 381ac35ff17SAlexander V. Chernikov } else if (tei->subtype == AF_INET6) { 3829f7d47b0SAlexander V. Chernikov /* IPv6 case */ 3839f7d47b0SAlexander V. Chernikov if (mlen > 128) 3849f7d47b0SAlexander V. Chernikov return (EINVAL); 3859f7d47b0SAlexander V. Chernikov xent = malloc(sizeof(*xent), M_IPFW_TBL, M_WAITOK | M_ZERO); 3869f7d47b0SAlexander V. Chernikov xent->value = tei->value; 387e0a8b9eeSAlexander V. Chernikov xent->masklen = mlen; 3882e324d29SAlexander V. Chernikov 3892e324d29SAlexander V. Chernikov addr = (struct sockaddr *)&xent->addr6; 3902e324d29SAlexander V. Chernikov mask = (struct sockaddr *)&tb->addr.a6.ma; 3919f7d47b0SAlexander V. Chernikov tb->ent_ptr = xent; 3929f7d47b0SAlexander V. Chernikov #endif 3939f7d47b0SAlexander V. Chernikov } else { 3949f7d47b0SAlexander V. Chernikov /* Unknown CIDR type */ 3959f7d47b0SAlexander V. Chernikov return (EINVAL); 3969f7d47b0SAlexander V. Chernikov } 3979f7d47b0SAlexander V. Chernikov 3982e324d29SAlexander V. Chernikov tei_to_sockaddr_ent(tei, addr, mask, &set_mask); 3992e324d29SAlexander V. Chernikov /* Set pointers */ 4002e324d29SAlexander V. Chernikov tb->addr_ptr = addr; 4012e324d29SAlexander V. Chernikov if (set_mask != 0) 4022e324d29SAlexander V. Chernikov tb->mask_ptr = mask; 4032e324d29SAlexander V. Chernikov 4049f7d47b0SAlexander V. Chernikov return (0); 4059f7d47b0SAlexander V. Chernikov } 4069f7d47b0SAlexander V. Chernikov 4079f7d47b0SAlexander V. Chernikov static int 408*a399f8beSAlexander V. Chernikov ta_add_radix(void *ta_state, struct table_info *ti, struct tentry_info *tei, 409b6ee846eSAlexander V. Chernikov void *ta_buf, uint32_t *pnum) 4109f7d47b0SAlexander V. Chernikov { 4119f7d47b0SAlexander V. Chernikov struct radix_node_head *rnh; 4129f7d47b0SAlexander V. Chernikov struct radix_node *rn; 4139f7d47b0SAlexander V. Chernikov struct ta_buf_cidr *tb; 414648e8380SAlexander V. Chernikov uint32_t *old_value, value; 4159f7d47b0SAlexander V. Chernikov 4169f7d47b0SAlexander V. Chernikov tb = (struct ta_buf_cidr *)ta_buf; 4179f7d47b0SAlexander V. Chernikov 418ac35ff17SAlexander V. Chernikov if (tei->subtype == AF_INET) 4199f7d47b0SAlexander V. Chernikov rnh = ti->state; 4209f7d47b0SAlexander V. Chernikov else 4219f7d47b0SAlexander V. Chernikov rnh = ti->xstate; 4229f7d47b0SAlexander V. Chernikov 4234c0c07a5SAlexander V. Chernikov /* Search for an entry first */ 4244c0c07a5SAlexander V. Chernikov rn = rnh->rnh_lookup(tb->addr_ptr, tb->mask_ptr, rnh); 4254c0c07a5SAlexander V. Chernikov if (rn != NULL) { 426ac35ff17SAlexander V. Chernikov if ((tei->flags & TEI_FLAGS_UPDATE) == 0) 4279f7d47b0SAlexander V. Chernikov return (EEXIST); 428ac35ff17SAlexander V. Chernikov /* Record already exists. Update value if we're asked to */ 429648e8380SAlexander V. Chernikov if (tei->subtype == AF_INET) 430648e8380SAlexander V. Chernikov old_value = &((struct radix_cidr_entry *)rn)->value; 431648e8380SAlexander V. Chernikov else 432648e8380SAlexander V. Chernikov old_value = &((struct radix_cidr_xentry *)rn)->value; 433648e8380SAlexander V. Chernikov 434648e8380SAlexander V. Chernikov value = *old_value; 435648e8380SAlexander V. Chernikov *old_value = tei->value; 436648e8380SAlexander V. Chernikov tei->value = value; 437ac35ff17SAlexander V. Chernikov 438ac35ff17SAlexander V. Chernikov /* Indicate that update has happened instead of addition */ 439ac35ff17SAlexander V. Chernikov tei->flags |= TEI_FLAGS_UPDATED; 440adea6201SAlexander V. Chernikov *pnum = 0; 441e0a8b9eeSAlexander V. Chernikov 442e0a8b9eeSAlexander V. Chernikov return (0); 443ac35ff17SAlexander V. Chernikov } 444ac35ff17SAlexander V. Chernikov 4454c0c07a5SAlexander V. Chernikov if ((tei->flags & TEI_FLAGS_DONTADD) != 0) 4464c0c07a5SAlexander V. Chernikov return (EFBIG); 4474c0c07a5SAlexander V. Chernikov 4484c0c07a5SAlexander V. Chernikov rn = rnh->rnh_addaddr(tb->addr_ptr, tb->mask_ptr, rnh, tb->ent_ptr); 4494c0c07a5SAlexander V. Chernikov if (rn == NULL) { 4504c0c07a5SAlexander V. Chernikov /* Unknown error */ 4514c0c07a5SAlexander V. Chernikov return (EINVAL); 4524c0c07a5SAlexander V. Chernikov } 4534c0c07a5SAlexander V. Chernikov 454ac35ff17SAlexander V. Chernikov tb->ent_ptr = NULL; 455adea6201SAlexander V. Chernikov *pnum = 1; 4569f7d47b0SAlexander V. Chernikov 4579f7d47b0SAlexander V. Chernikov return (0); 4589f7d47b0SAlexander V. Chernikov } 4599f7d47b0SAlexander V. Chernikov 4609f7d47b0SAlexander V. Chernikov static int 461*a399f8beSAlexander V. Chernikov ta_prepare_del_radix(struct ip_fw_chain *ch, struct tentry_info *tei, 46268394ec8SAlexander V. Chernikov void *ta_buf) 4639f7d47b0SAlexander V. Chernikov { 4649f7d47b0SAlexander V. Chernikov struct ta_buf_cidr *tb; 4652e324d29SAlexander V. Chernikov struct sockaddr *addr, *mask; 4662e324d29SAlexander V. Chernikov int mlen, set_mask; 4679f7d47b0SAlexander V. Chernikov 4689f7d47b0SAlexander V. Chernikov tb = (struct ta_buf_cidr *)ta_buf; 4699f7d47b0SAlexander V. Chernikov 4709f7d47b0SAlexander V. Chernikov mlen = tei->masklen; 4712e324d29SAlexander V. Chernikov set_mask = 0; 4729f7d47b0SAlexander V. Chernikov 473ac35ff17SAlexander V. Chernikov if (tei->subtype == AF_INET) { 474e0a8b9eeSAlexander V. Chernikov if (mlen > 32) 475e0a8b9eeSAlexander V. Chernikov return (EINVAL); 4762e324d29SAlexander V. Chernikov 4772e324d29SAlexander V. Chernikov addr = (struct sockaddr *)&tb->addr.a4.sa; 4782e324d29SAlexander V. Chernikov mask = (struct sockaddr *)&tb->addr.a4.ma; 4799f7d47b0SAlexander V. Chernikov #ifdef INET6 480ac35ff17SAlexander V. Chernikov } else if (tei->subtype == AF_INET6) { 4819f7d47b0SAlexander V. Chernikov if (mlen > 128) 4829f7d47b0SAlexander V. Chernikov return (EINVAL); 4832e324d29SAlexander V. Chernikov 4842e324d29SAlexander V. Chernikov addr = (struct sockaddr *)&tb->addr.a6.sa; 4852e324d29SAlexander V. Chernikov mask = (struct sockaddr *)&tb->addr.a6.ma; 4869f7d47b0SAlexander V. Chernikov #endif 4879f7d47b0SAlexander V. Chernikov } else 4889f7d47b0SAlexander V. Chernikov return (EINVAL); 4899f7d47b0SAlexander V. Chernikov 4902e324d29SAlexander V. Chernikov tei_to_sockaddr_ent(tei, addr, mask, &set_mask); 4912e324d29SAlexander V. Chernikov tb->addr_ptr = addr; 4922e324d29SAlexander V. Chernikov if (set_mask != 0) 4932e324d29SAlexander V. Chernikov tb->mask_ptr = mask; 4942e324d29SAlexander V. Chernikov 4959f7d47b0SAlexander V. Chernikov return (0); 4969f7d47b0SAlexander V. Chernikov } 4979f7d47b0SAlexander V. Chernikov 4989f7d47b0SAlexander V. Chernikov static int 499*a399f8beSAlexander V. Chernikov ta_del_radix(void *ta_state, struct table_info *ti, struct tentry_info *tei, 500b6ee846eSAlexander V. Chernikov void *ta_buf, uint32_t *pnum) 5019f7d47b0SAlexander V. Chernikov { 5029f7d47b0SAlexander V. Chernikov struct radix_node_head *rnh; 5039f7d47b0SAlexander V. Chernikov struct radix_node *rn; 5049f7d47b0SAlexander V. Chernikov struct ta_buf_cidr *tb; 5059f7d47b0SAlexander V. Chernikov 5069f7d47b0SAlexander V. Chernikov tb = (struct ta_buf_cidr *)ta_buf; 5079f7d47b0SAlexander V. Chernikov 508ac35ff17SAlexander V. Chernikov if (tei->subtype == AF_INET) 5099f7d47b0SAlexander V. Chernikov rnh = ti->state; 5109f7d47b0SAlexander V. Chernikov else 5119f7d47b0SAlexander V. Chernikov rnh = ti->xstate; 5129f7d47b0SAlexander V. Chernikov 5139f7d47b0SAlexander V. Chernikov rn = rnh->rnh_deladdr(tb->addr_ptr, tb->mask_ptr, rnh); 5149f7d47b0SAlexander V. Chernikov 515648e8380SAlexander V. Chernikov /* Save entry value to @tei */ 516648e8380SAlexander V. Chernikov if (tei->subtype == AF_INET) 517648e8380SAlexander V. Chernikov tei->value = ((struct radix_cidr_entry *)rn)->value; 518648e8380SAlexander V. Chernikov else 519648e8380SAlexander V. Chernikov tei->value = ((struct radix_cidr_xentry *)rn)->value; 520648e8380SAlexander V. Chernikov 5219f7d47b0SAlexander V. Chernikov tb->ent_ptr = rn; 5229f7d47b0SAlexander V. Chernikov 5239f7d47b0SAlexander V. Chernikov if (rn == NULL) 52481d3153dSAlexander V. Chernikov return (ENOENT); 5259f7d47b0SAlexander V. Chernikov 526adea6201SAlexander V. Chernikov *pnum = 1; 527adea6201SAlexander V. Chernikov 5289f7d47b0SAlexander V. Chernikov return (0); 5299f7d47b0SAlexander V. Chernikov } 5309f7d47b0SAlexander V. Chernikov 5319f7d47b0SAlexander V. Chernikov static void 532*a399f8beSAlexander V. Chernikov ta_flush_radix_entry(struct ip_fw_chain *ch, struct tentry_info *tei, 53368394ec8SAlexander V. Chernikov void *ta_buf) 5349f7d47b0SAlexander V. Chernikov { 5359f7d47b0SAlexander V. Chernikov struct ta_buf_cidr *tb; 5369f7d47b0SAlexander V. Chernikov 5379f7d47b0SAlexander V. Chernikov tb = (struct ta_buf_cidr *)ta_buf; 5389f7d47b0SAlexander V. Chernikov 539ac35ff17SAlexander V. Chernikov if (tb->ent_ptr != NULL) 5409f7d47b0SAlexander V. Chernikov free(tb->ent_ptr, M_IPFW_TBL); 5419f7d47b0SAlexander V. Chernikov } 5429f7d47b0SAlexander V. Chernikov 543b6ee846eSAlexander V. Chernikov static int 544b6ee846eSAlexander V. Chernikov ta_has_space_radix(void *ta_state, struct table_info *ti, uint32_t count, 545b6ee846eSAlexander V. Chernikov uint64_t *pflags) 546b6ee846eSAlexander V. Chernikov { 547b6ee846eSAlexander V. Chernikov 548b6ee846eSAlexander V. Chernikov /* 5490bce0c23SAlexander V. Chernikov * radix does not require additional memory allocations 550b6ee846eSAlexander V. Chernikov * other than nodes itself. Adding new masks to the tree do 551b6ee846eSAlexander V. Chernikov * but we don't have any API to call (and we don't known which 552b6ee846eSAlexander V. Chernikov * sizes do we need). 553b6ee846eSAlexander V. Chernikov */ 554b6ee846eSAlexander V. Chernikov return (1); 555b6ee846eSAlexander V. Chernikov } 556b6ee846eSAlexander V. Chernikov 55774b941f0SAlexander V. Chernikov struct table_algo cidr_radix = { 558adea6201SAlexander V. Chernikov .name = "cidr:radix", 5599d099b4fSAlexander V. Chernikov .type = IPFW_TABLE_CIDR, 56057a1cf95SAlexander V. Chernikov .flags = TA_FLAG_DEFAULT, 56157a1cf95SAlexander V. Chernikov .ta_buf_size = sizeof(struct ta_buf_cidr), 5629f7d47b0SAlexander V. Chernikov .init = ta_init_radix, 5639f7d47b0SAlexander V. Chernikov .destroy = ta_destroy_radix, 564*a399f8beSAlexander V. Chernikov .prepare_add = ta_prepare_add_radix, 565*a399f8beSAlexander V. Chernikov .prepare_del = ta_prepare_del_radix, 566*a399f8beSAlexander V. Chernikov .add = ta_add_radix, 567*a399f8beSAlexander V. Chernikov .del = ta_del_radix, 568*a399f8beSAlexander V. Chernikov .flush_entry = ta_flush_radix_entry, 5699f7d47b0SAlexander V. Chernikov .foreach = ta_foreach_radix, 57081d3153dSAlexander V. Chernikov .dump_tentry = ta_dump_radix_tentry, 57181d3153dSAlexander V. Chernikov .find_tentry = ta_find_radix_tentry, 572b6ee846eSAlexander V. Chernikov .has_space = ta_has_space_radix, 5739f7d47b0SAlexander V. Chernikov }; 5749f7d47b0SAlexander V. Chernikov 5759f7d47b0SAlexander V. Chernikov 5769f7d47b0SAlexander V. Chernikov /* 57774b941f0SAlexander V. Chernikov * cidr:hash cmds 57874b941f0SAlexander V. Chernikov * 57974b941f0SAlexander V. Chernikov * 58074b941f0SAlexander V. Chernikov * ti->data: 58174b941f0SAlexander V. Chernikov * [inv.mask4][inv.mask6][log2hsize4][log2hsize6] 58274b941f0SAlexander V. Chernikov * [ 8][ 8[ 8][ 8] 58374b941f0SAlexander V. Chernikov * 58474b941f0SAlexander V. Chernikov * inv.mask4: 32 - mask 58574b941f0SAlexander V. Chernikov * inv.mask6: 58674b941f0SAlexander V. Chernikov * 1) _slow lookup: mask 58774b941f0SAlexander V. Chernikov * 2) _aligned: (128 - mask) / 8 58874b941f0SAlexander V. Chernikov * 3) _64: 8 589ce2817b5SAlexander V. Chernikov * 590ce2817b5SAlexander V. Chernikov * 591ce2817b5SAlexander V. Chernikov * pflags: 592ce2817b5SAlexander V. Chernikov * [v4=1/v6=0][hsize] 593ce2817b5SAlexander V. Chernikov * [ 32][ 32] 59474b941f0SAlexander V. Chernikov */ 59574b941f0SAlexander V. Chernikov 59674b941f0SAlexander V. Chernikov struct chashentry; 59774b941f0SAlexander V. Chernikov 59874b941f0SAlexander V. Chernikov SLIST_HEAD(chashbhead, chashentry); 59974b941f0SAlexander V. Chernikov 60074b941f0SAlexander V. Chernikov struct chash_cfg { 60174b941f0SAlexander V. Chernikov struct chashbhead *head4; 60274b941f0SAlexander V. Chernikov struct chashbhead *head6; 60374b941f0SAlexander V. Chernikov size_t size4; 60474b941f0SAlexander V. Chernikov size_t size6; 605ce2817b5SAlexander V. Chernikov size_t items4; 606ce2817b5SAlexander V. Chernikov size_t items6; 60774b941f0SAlexander V. Chernikov uint8_t mask4; 60874b941f0SAlexander V. Chernikov uint8_t mask6; 60974b941f0SAlexander V. Chernikov }; 61074b941f0SAlexander V. Chernikov 61174b941f0SAlexander V. Chernikov struct chashentry { 61274b941f0SAlexander V. Chernikov SLIST_ENTRY(chashentry) next; 61374b941f0SAlexander V. Chernikov uint32_t value; 61474b941f0SAlexander V. Chernikov uint32_t type; 61574b941f0SAlexander V. Chernikov union { 61674b941f0SAlexander V. Chernikov uint32_t a4; /* Host format */ 61774b941f0SAlexander V. Chernikov struct in6_addr a6; /* Network format */ 61874b941f0SAlexander V. Chernikov } a; 61974b941f0SAlexander V. Chernikov }; 62074b941f0SAlexander V. Chernikov 6210bce0c23SAlexander V. Chernikov struct ta_buf_chash 6220bce0c23SAlexander V. Chernikov { 6230bce0c23SAlexander V. Chernikov void *ent_ptr; 6240bce0c23SAlexander V. Chernikov struct chashentry ent; 6250bce0c23SAlexander V. Chernikov }; 6260bce0c23SAlexander V. Chernikov 6270bce0c23SAlexander V. Chernikov 62874b941f0SAlexander V. Chernikov static __inline uint32_t 62974b941f0SAlexander V. Chernikov hash_ip(uint32_t addr, int hsize) 63074b941f0SAlexander V. Chernikov { 63174b941f0SAlexander V. Chernikov 63274b941f0SAlexander V. Chernikov return (addr % (hsize - 1)); 63374b941f0SAlexander V. Chernikov } 63474b941f0SAlexander V. Chernikov 63574b941f0SAlexander V. Chernikov static __inline uint32_t 63674b941f0SAlexander V. Chernikov hash_ip6(struct in6_addr *addr6, int hsize) 63774b941f0SAlexander V. Chernikov { 63874b941f0SAlexander V. Chernikov uint32_t i; 63974b941f0SAlexander V. Chernikov 64074b941f0SAlexander V. Chernikov i = addr6->s6_addr32[0] ^ addr6->s6_addr32[1] ^ 64174b941f0SAlexander V. Chernikov addr6->s6_addr32[2] ^ addr6->s6_addr32[3]; 64274b941f0SAlexander V. Chernikov 64374b941f0SAlexander V. Chernikov return (i % (hsize - 1)); 64474b941f0SAlexander V. Chernikov } 64574b941f0SAlexander V. Chernikov 64674b941f0SAlexander V. Chernikov 64774b941f0SAlexander V. Chernikov static __inline uint16_t 64874b941f0SAlexander V. Chernikov hash_ip64(struct in6_addr *addr6, int hsize) 64974b941f0SAlexander V. Chernikov { 65074b941f0SAlexander V. Chernikov uint32_t i; 65174b941f0SAlexander V. Chernikov 65274b941f0SAlexander V. Chernikov i = addr6->s6_addr32[0] ^ addr6->s6_addr32[1]; 65374b941f0SAlexander V. Chernikov 65474b941f0SAlexander V. Chernikov return (i % (hsize - 1)); 65574b941f0SAlexander V. Chernikov } 65674b941f0SAlexander V. Chernikov 65774b941f0SAlexander V. Chernikov 65874b941f0SAlexander V. Chernikov static __inline uint32_t 65974b941f0SAlexander V. Chernikov hash_ip6_slow(struct in6_addr *addr6, void *key, int mask, int hsize) 66074b941f0SAlexander V. Chernikov { 66174b941f0SAlexander V. Chernikov struct in6_addr mask6; 66274b941f0SAlexander V. Chernikov 66374b941f0SAlexander V. Chernikov ipv6_writemask(&mask6, mask); 66474b941f0SAlexander V. Chernikov memcpy(addr6, key, sizeof(struct in6_addr)); 66574b941f0SAlexander V. Chernikov APPLY_MASK(addr6, &mask6); 66674b941f0SAlexander V. Chernikov return (hash_ip6(addr6, hsize)); 66774b941f0SAlexander V. Chernikov } 66874b941f0SAlexander V. Chernikov 66974b941f0SAlexander V. Chernikov static __inline uint32_t 67074b941f0SAlexander V. Chernikov hash_ip6_al(struct in6_addr *addr6, void *key, int mask, int hsize) 67174b941f0SAlexander V. Chernikov { 67274b941f0SAlexander V. Chernikov uint64_t *paddr; 67374b941f0SAlexander V. Chernikov 67474b941f0SAlexander V. Chernikov paddr = (uint64_t *)addr6; 67574b941f0SAlexander V. Chernikov *paddr = 0; 67674b941f0SAlexander V. Chernikov *(paddr + 1) = 0; 67774b941f0SAlexander V. Chernikov memcpy(addr6, key, mask); 67874b941f0SAlexander V. Chernikov return (hash_ip6(addr6, hsize)); 67974b941f0SAlexander V. Chernikov } 68074b941f0SAlexander V. Chernikov 68174b941f0SAlexander V. Chernikov static int 68274b941f0SAlexander V. Chernikov ta_lookup_chash_slow(struct table_info *ti, void *key, uint32_t keylen, 68374b941f0SAlexander V. Chernikov uint32_t *val) 68474b941f0SAlexander V. Chernikov { 68574b941f0SAlexander V. Chernikov struct chashbhead *head; 68674b941f0SAlexander V. Chernikov struct chashentry *ent; 68774b941f0SAlexander V. Chernikov uint16_t hash, hsize; 68874b941f0SAlexander V. Chernikov uint8_t imask; 68974b941f0SAlexander V. Chernikov 69074b941f0SAlexander V. Chernikov if (keylen == sizeof(in_addr_t)) { 69174b941f0SAlexander V. Chernikov head = (struct chashbhead *)ti->state; 69274b941f0SAlexander V. Chernikov imask = ti->data >> 24; 69374b941f0SAlexander V. Chernikov hsize = 1 << ((ti->data & 0xFFFF) >> 8); 69474b941f0SAlexander V. Chernikov uint32_t a; 69574b941f0SAlexander V. Chernikov a = ntohl(*((in_addr_t *)key)); 69674b941f0SAlexander V. Chernikov a = a >> imask; 69774b941f0SAlexander V. Chernikov hash = hash_ip(a, hsize); 69874b941f0SAlexander V. Chernikov SLIST_FOREACH(ent, &head[hash], next) { 69974b941f0SAlexander V. Chernikov if (ent->a.a4 == a) { 70074b941f0SAlexander V. Chernikov *val = ent->value; 70174b941f0SAlexander V. Chernikov return (1); 70274b941f0SAlexander V. Chernikov } 70374b941f0SAlexander V. Chernikov } 70474b941f0SAlexander V. Chernikov } else { 70574b941f0SAlexander V. Chernikov /* IPv6: worst scenario: non-round mask */ 70674b941f0SAlexander V. Chernikov struct in6_addr addr6; 70774b941f0SAlexander V. Chernikov head = (struct chashbhead *)ti->xstate; 70874b941f0SAlexander V. Chernikov imask = (ti->data & 0xFF0000) >> 16; 70974b941f0SAlexander V. Chernikov hsize = 1 << (ti->data & 0xFF); 71074b941f0SAlexander V. Chernikov hash = hash_ip6_slow(&addr6, key, imask, hsize); 71174b941f0SAlexander V. Chernikov SLIST_FOREACH(ent, &head[hash], next) { 71274b941f0SAlexander V. Chernikov if (memcmp(&ent->a.a6, &addr6, 16) == 0) { 71374b941f0SAlexander V. Chernikov *val = ent->value; 71474b941f0SAlexander V. Chernikov return (1); 71574b941f0SAlexander V. Chernikov } 71674b941f0SAlexander V. Chernikov } 71774b941f0SAlexander V. Chernikov } 71874b941f0SAlexander V. Chernikov 71974b941f0SAlexander V. Chernikov return (0); 72074b941f0SAlexander V. Chernikov } 72174b941f0SAlexander V. Chernikov 72274b941f0SAlexander V. Chernikov static int 72374b941f0SAlexander V. Chernikov ta_lookup_chash_aligned(struct table_info *ti, void *key, uint32_t keylen, 72474b941f0SAlexander V. Chernikov uint32_t *val) 72574b941f0SAlexander V. Chernikov { 72674b941f0SAlexander V. Chernikov struct chashbhead *head; 72774b941f0SAlexander V. Chernikov struct chashentry *ent; 72874b941f0SAlexander V. Chernikov uint16_t hash, hsize; 72974b941f0SAlexander V. Chernikov uint8_t imask; 73074b941f0SAlexander V. Chernikov 73174b941f0SAlexander V. Chernikov if (keylen == sizeof(in_addr_t)) { 73274b941f0SAlexander V. Chernikov head = (struct chashbhead *)ti->state; 73374b941f0SAlexander V. Chernikov imask = ti->data >> 24; 73474b941f0SAlexander V. Chernikov hsize = 1 << ((ti->data & 0xFFFF) >> 8); 73574b941f0SAlexander V. Chernikov uint32_t a; 73674b941f0SAlexander V. Chernikov a = ntohl(*((in_addr_t *)key)); 73774b941f0SAlexander V. Chernikov a = a >> imask; 73874b941f0SAlexander V. Chernikov hash = hash_ip(a, hsize); 73974b941f0SAlexander V. Chernikov SLIST_FOREACH(ent, &head[hash], next) { 74074b941f0SAlexander V. Chernikov if (ent->a.a4 == a) { 74174b941f0SAlexander V. Chernikov *val = ent->value; 74274b941f0SAlexander V. Chernikov return (1); 74374b941f0SAlexander V. Chernikov } 74474b941f0SAlexander V. Chernikov } 74574b941f0SAlexander V. Chernikov } else { 74674b941f0SAlexander V. Chernikov /* IPv6: aligned to 8bit mask */ 74774b941f0SAlexander V. Chernikov struct in6_addr addr6; 74874b941f0SAlexander V. Chernikov uint64_t *paddr, *ptmp; 74974b941f0SAlexander V. Chernikov head = (struct chashbhead *)ti->xstate; 75074b941f0SAlexander V. Chernikov imask = (ti->data & 0xFF0000) >> 16; 75174b941f0SAlexander V. Chernikov hsize = 1 << (ti->data & 0xFF); 75274b941f0SAlexander V. Chernikov 75374b941f0SAlexander V. Chernikov hash = hash_ip6_al(&addr6, key, imask, hsize); 75474b941f0SAlexander V. Chernikov paddr = (uint64_t *)&addr6; 75574b941f0SAlexander V. Chernikov SLIST_FOREACH(ent, &head[hash], next) { 75674b941f0SAlexander V. Chernikov ptmp = (uint64_t *)&ent->a.a6; 75774b941f0SAlexander V. Chernikov if (paddr[0] == ptmp[0] && paddr[1] == ptmp[1]) { 75874b941f0SAlexander V. Chernikov *val = ent->value; 75974b941f0SAlexander V. Chernikov return (1); 76074b941f0SAlexander V. Chernikov } 76174b941f0SAlexander V. Chernikov } 76274b941f0SAlexander V. Chernikov } 76374b941f0SAlexander V. Chernikov 76474b941f0SAlexander V. Chernikov return (0); 76574b941f0SAlexander V. Chernikov } 76674b941f0SAlexander V. Chernikov 76774b941f0SAlexander V. Chernikov static int 76874b941f0SAlexander V. Chernikov ta_lookup_chash_64(struct table_info *ti, void *key, uint32_t keylen, 76974b941f0SAlexander V. Chernikov uint32_t *val) 77074b941f0SAlexander V. Chernikov { 77174b941f0SAlexander V. Chernikov struct chashbhead *head; 77274b941f0SAlexander V. Chernikov struct chashentry *ent; 77374b941f0SAlexander V. Chernikov uint16_t hash, hsize; 77474b941f0SAlexander V. Chernikov uint8_t imask; 77574b941f0SAlexander V. Chernikov 77674b941f0SAlexander V. Chernikov if (keylen == sizeof(in_addr_t)) { 77774b941f0SAlexander V. Chernikov head = (struct chashbhead *)ti->state; 77874b941f0SAlexander V. Chernikov imask = ti->data >> 24; 77974b941f0SAlexander V. Chernikov hsize = 1 << ((ti->data & 0xFFFF) >> 8); 78074b941f0SAlexander V. Chernikov uint32_t a; 78174b941f0SAlexander V. Chernikov a = ntohl(*((in_addr_t *)key)); 78274b941f0SAlexander V. Chernikov a = a >> imask; 78374b941f0SAlexander V. Chernikov hash = hash_ip(a, hsize); 78474b941f0SAlexander V. Chernikov SLIST_FOREACH(ent, &head[hash], next) { 78574b941f0SAlexander V. Chernikov if (ent->a.a4 == a) { 78674b941f0SAlexander V. Chernikov *val = ent->value; 78774b941f0SAlexander V. Chernikov return (1); 78874b941f0SAlexander V. Chernikov } 78974b941f0SAlexander V. Chernikov } 79074b941f0SAlexander V. Chernikov } else { 79174b941f0SAlexander V. Chernikov /* IPv6: /64 */ 79274b941f0SAlexander V. Chernikov uint64_t a6, *paddr; 79374b941f0SAlexander V. Chernikov head = (struct chashbhead *)ti->xstate; 79474b941f0SAlexander V. Chernikov paddr = (uint64_t *)key; 79574b941f0SAlexander V. Chernikov hsize = 1 << (ti->data & 0xFF); 79674b941f0SAlexander V. Chernikov a6 = *paddr; 79774b941f0SAlexander V. Chernikov hash = hash_ip64((struct in6_addr *)key, hsize); 79874b941f0SAlexander V. Chernikov SLIST_FOREACH(ent, &head[hash], next) { 79974b941f0SAlexander V. Chernikov paddr = (uint64_t *)&ent->a.a6; 80074b941f0SAlexander V. Chernikov if (a6 == *paddr) { 80174b941f0SAlexander V. Chernikov *val = ent->value; 80274b941f0SAlexander V. Chernikov return (1); 80374b941f0SAlexander V. Chernikov } 80474b941f0SAlexander V. Chernikov } 80574b941f0SAlexander V. Chernikov } 80674b941f0SAlexander V. Chernikov 80774b941f0SAlexander V. Chernikov return (0); 80874b941f0SAlexander V. Chernikov } 80974b941f0SAlexander V. Chernikov 81074b941f0SAlexander V. Chernikov static int 8110bce0c23SAlexander V. Chernikov chash_parse_opts(struct chash_cfg *cfg, char *data) 81274b941f0SAlexander V. Chernikov { 81374b941f0SAlexander V. Chernikov char *pdel, *pend, *s; 81474b941f0SAlexander V. Chernikov int mask4, mask6; 81574b941f0SAlexander V. Chernikov 8160bce0c23SAlexander V. Chernikov mask4 = cfg->mask4; 8170bce0c23SAlexander V. Chernikov mask6 = cfg->mask6; 81874b941f0SAlexander V. Chernikov 81974b941f0SAlexander V. Chernikov if (data == NULL) 82074b941f0SAlexander V. Chernikov return (0); 82174b941f0SAlexander V. Chernikov if ((pdel = strchr(data, ' ')) == NULL) 82274b941f0SAlexander V. Chernikov return (0); 82374b941f0SAlexander V. Chernikov while (*pdel == ' ') 82474b941f0SAlexander V. Chernikov pdel++; 82574b941f0SAlexander V. Chernikov if (strncmp(pdel, "masks=", 6) != 0) 82674b941f0SAlexander V. Chernikov return (EINVAL); 82774b941f0SAlexander V. Chernikov if ((s = strchr(pdel, ' ')) != NULL) 82874b941f0SAlexander V. Chernikov *s++ = '\0'; 82974b941f0SAlexander V. Chernikov 83074b941f0SAlexander V. Chernikov pdel += 6; 83174b941f0SAlexander V. Chernikov /* Need /XX[,/YY] */ 83274b941f0SAlexander V. Chernikov if (*pdel++ != '/') 83374b941f0SAlexander V. Chernikov return (EINVAL); 83474b941f0SAlexander V. Chernikov mask4 = strtol(pdel, &pend, 10); 83574b941f0SAlexander V. Chernikov if (*pend == ',') { 83674b941f0SAlexander V. Chernikov /* ,/YY */ 83774b941f0SAlexander V. Chernikov pdel = pend + 1; 83874b941f0SAlexander V. Chernikov if (*pdel++ != '/') 83974b941f0SAlexander V. Chernikov return (EINVAL); 84074b941f0SAlexander V. Chernikov mask6 = strtol(pdel, &pend, 10); 84174b941f0SAlexander V. Chernikov if (*pend != '\0') 84274b941f0SAlexander V. Chernikov return (EINVAL); 84374b941f0SAlexander V. Chernikov } else if (*pend != '\0') 84474b941f0SAlexander V. Chernikov return (EINVAL); 84574b941f0SAlexander V. Chernikov 84674b941f0SAlexander V. Chernikov if (mask4 < 0 || mask4 > 32 || mask6 < 0 || mask6 > 128) 84774b941f0SAlexander V. Chernikov return (EINVAL); 84874b941f0SAlexander V. Chernikov 8490bce0c23SAlexander V. Chernikov cfg->mask4 = mask4; 8500bce0c23SAlexander V. Chernikov cfg->mask6 = mask6; 85174b941f0SAlexander V. Chernikov 85274b941f0SAlexander V. Chernikov return (0); 85374b941f0SAlexander V. Chernikov } 85474b941f0SAlexander V. Chernikov 85574b941f0SAlexander V. Chernikov static void 85674b941f0SAlexander V. Chernikov ta_print_chash_config(void *ta_state, struct table_info *ti, char *buf, 85774b941f0SAlexander V. Chernikov size_t bufsize) 85874b941f0SAlexander V. Chernikov { 8590bce0c23SAlexander V. Chernikov struct chash_cfg *cfg; 86074b941f0SAlexander V. Chernikov 8610bce0c23SAlexander V. Chernikov cfg = (struct chash_cfg *)ta_state; 86274b941f0SAlexander V. Chernikov 8630bce0c23SAlexander V. Chernikov if (cfg->mask4 != 32 || cfg->mask6 != 128) 86474b941f0SAlexander V. Chernikov snprintf(buf, bufsize, "%s masks=/%d,/%d", "cidr:hash", 8650bce0c23SAlexander V. Chernikov cfg->mask4, cfg->mask6); 86674b941f0SAlexander V. Chernikov else 86774b941f0SAlexander V. Chernikov snprintf(buf, bufsize, "%s", "cidr:hash"); 86874b941f0SAlexander V. Chernikov } 86974b941f0SAlexander V. Chernikov 870914bffb6SAlexander V. Chernikov static int 871914bffb6SAlexander V. Chernikov log2(uint32_t v) 872914bffb6SAlexander V. Chernikov { 873914bffb6SAlexander V. Chernikov uint32_t r; 874914bffb6SAlexander V. Chernikov 875914bffb6SAlexander V. Chernikov r = 0; 876914bffb6SAlexander V. Chernikov while (v >>= 1) 877914bffb6SAlexander V. Chernikov r++; 878914bffb6SAlexander V. Chernikov 879914bffb6SAlexander V. Chernikov return (r); 880914bffb6SAlexander V. Chernikov } 88174b941f0SAlexander V. Chernikov 88274b941f0SAlexander V. Chernikov /* 88374b941f0SAlexander V. Chernikov * New table. 88474b941f0SAlexander V. Chernikov * We assume 'data' to be either NULL or the following format: 88574b941f0SAlexander V. Chernikov * 'cidr:hash [masks=/32[,/128]]' 88674b941f0SAlexander V. Chernikov */ 88774b941f0SAlexander V. Chernikov static int 88874b941f0SAlexander V. Chernikov ta_init_chash(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti, 889914bffb6SAlexander V. Chernikov char *data, uint8_t tflags) 89074b941f0SAlexander V. Chernikov { 89174b941f0SAlexander V. Chernikov int error, i; 892914bffb6SAlexander V. Chernikov uint32_t hsize; 8930bce0c23SAlexander V. Chernikov struct chash_cfg *cfg; 89474b941f0SAlexander V. Chernikov 8950bce0c23SAlexander V. Chernikov cfg = malloc(sizeof(struct chash_cfg), M_IPFW, M_WAITOK | M_ZERO); 89674b941f0SAlexander V. Chernikov 8970bce0c23SAlexander V. Chernikov cfg->mask4 = 32; 8980bce0c23SAlexander V. Chernikov cfg->mask6 = 128; 89974b941f0SAlexander V. Chernikov 9000bce0c23SAlexander V. Chernikov if ((error = chash_parse_opts(cfg, data)) != 0) { 9010bce0c23SAlexander V. Chernikov free(cfg, M_IPFW); 90274b941f0SAlexander V. Chernikov return (error); 90374b941f0SAlexander V. Chernikov } 90474b941f0SAlexander V. Chernikov 9050bce0c23SAlexander V. Chernikov cfg->size4 = 128; 9060bce0c23SAlexander V. Chernikov cfg->size6 = 128; 90774b941f0SAlexander V. Chernikov 9080bce0c23SAlexander V. Chernikov cfg->head4 = malloc(sizeof(struct chashbhead) * cfg->size4, M_IPFW, 90974b941f0SAlexander V. Chernikov M_WAITOK | M_ZERO); 9100bce0c23SAlexander V. Chernikov cfg->head6 = malloc(sizeof(struct chashbhead) * cfg->size6, M_IPFW, 91174b941f0SAlexander V. Chernikov M_WAITOK | M_ZERO); 9120bce0c23SAlexander V. Chernikov for (i = 0; i < cfg->size4; i++) 9130bce0c23SAlexander V. Chernikov SLIST_INIT(&cfg->head4[i]); 9140bce0c23SAlexander V. Chernikov for (i = 0; i < cfg->size6; i++) 9150bce0c23SAlexander V. Chernikov SLIST_INIT(&cfg->head6[i]); 91674b941f0SAlexander V. Chernikov 91774b941f0SAlexander V. Chernikov 9180bce0c23SAlexander V. Chernikov *ta_state = cfg; 9190bce0c23SAlexander V. Chernikov ti->state = cfg->head4; 9200bce0c23SAlexander V. Chernikov ti->xstate = cfg->head6; 92174b941f0SAlexander V. Chernikov 92274b941f0SAlexander V. Chernikov /* Store data depending on v6 mask length */ 9230bce0c23SAlexander V. Chernikov hsize = log2(cfg->size4) << 8 | log2(cfg->size6); 9240bce0c23SAlexander V. Chernikov if (cfg->mask6 == 64) { 9250bce0c23SAlexander V. Chernikov ti->data = (32 - cfg->mask4) << 24 | (128 - cfg->mask6) << 16| 926914bffb6SAlexander V. Chernikov hsize; 92774b941f0SAlexander V. Chernikov ti->lookup = ta_lookup_chash_64; 9280bce0c23SAlexander V. Chernikov } else if ((cfg->mask6 % 8) == 0) { 9290bce0c23SAlexander V. Chernikov ti->data = (32 - cfg->mask4) << 24 | 9300bce0c23SAlexander V. Chernikov cfg->mask6 << 13 | hsize; 93174b941f0SAlexander V. Chernikov ti->lookup = ta_lookup_chash_aligned; 93274b941f0SAlexander V. Chernikov } else { 93374b941f0SAlexander V. Chernikov /* don't do that! */ 9340bce0c23SAlexander V. Chernikov ti->data = (32 - cfg->mask4) << 24 | 9350bce0c23SAlexander V. Chernikov cfg->mask6 << 16 | hsize; 93674b941f0SAlexander V. Chernikov ti->lookup = ta_lookup_chash_slow; 93774b941f0SAlexander V. Chernikov } 93874b941f0SAlexander V. Chernikov 93974b941f0SAlexander V. Chernikov return (0); 94074b941f0SAlexander V. Chernikov } 94174b941f0SAlexander V. Chernikov 94274b941f0SAlexander V. Chernikov static void 94374b941f0SAlexander V. Chernikov ta_destroy_chash(void *ta_state, struct table_info *ti) 94474b941f0SAlexander V. Chernikov { 9450bce0c23SAlexander V. Chernikov struct chash_cfg *cfg; 94674b941f0SAlexander V. Chernikov struct chashentry *ent, *ent_next; 94774b941f0SAlexander V. Chernikov int i; 94874b941f0SAlexander V. Chernikov 9490bce0c23SAlexander V. Chernikov cfg = (struct chash_cfg *)ta_state; 95074b941f0SAlexander V. Chernikov 9510bce0c23SAlexander V. Chernikov for (i = 0; i < cfg->size4; i++) 9520bce0c23SAlexander V. Chernikov SLIST_FOREACH_SAFE(ent, &cfg->head4[i], next, ent_next) 95374b941f0SAlexander V. Chernikov free(ent, M_IPFW_TBL); 95474b941f0SAlexander V. Chernikov 9550bce0c23SAlexander V. Chernikov for (i = 0; i < cfg->size6; i++) 9560bce0c23SAlexander V. Chernikov SLIST_FOREACH_SAFE(ent, &cfg->head6[i], next, ent_next) 95774b941f0SAlexander V. Chernikov free(ent, M_IPFW_TBL); 95874b941f0SAlexander V. Chernikov 9590bce0c23SAlexander V. Chernikov free(cfg->head4, M_IPFW); 9600bce0c23SAlexander V. Chernikov free(cfg->head6, M_IPFW); 961ce2817b5SAlexander V. Chernikov 9620bce0c23SAlexander V. Chernikov free(cfg, M_IPFW); 96374b941f0SAlexander V. Chernikov } 96474b941f0SAlexander V. Chernikov 96574b941f0SAlexander V. Chernikov static int 96674b941f0SAlexander V. Chernikov ta_dump_chash_tentry(void *ta_state, struct table_info *ti, void *e, 96774b941f0SAlexander V. Chernikov ipfw_obj_tentry *tent) 96874b941f0SAlexander V. Chernikov { 9690bce0c23SAlexander V. Chernikov struct chash_cfg *cfg; 97074b941f0SAlexander V. Chernikov struct chashentry *ent; 97174b941f0SAlexander V. Chernikov 9720bce0c23SAlexander V. Chernikov cfg = (struct chash_cfg *)ta_state; 97374b941f0SAlexander V. Chernikov ent = (struct chashentry *)e; 97474b941f0SAlexander V. Chernikov 97574b941f0SAlexander V. Chernikov if (ent->type == AF_INET) { 9760bce0c23SAlexander V. Chernikov tent->k.addr.s_addr = htonl(ent->a.a4 << (32 - cfg->mask4)); 9770bce0c23SAlexander V. Chernikov tent->masklen = cfg->mask4; 97874b941f0SAlexander V. Chernikov tent->subtype = AF_INET; 97974b941f0SAlexander V. Chernikov tent->value = ent->value; 98074b941f0SAlexander V. Chernikov #ifdef INET6 98174b941f0SAlexander V. Chernikov } else { 98274b941f0SAlexander V. Chernikov memcpy(&tent->k, &ent->a.a6, sizeof(struct in6_addr)); 9830bce0c23SAlexander V. Chernikov tent->masklen = cfg->mask6; 98474b941f0SAlexander V. Chernikov tent->subtype = AF_INET6; 98574b941f0SAlexander V. Chernikov tent->value = ent->value; 98674b941f0SAlexander V. Chernikov #endif 98774b941f0SAlexander V. Chernikov } 98874b941f0SAlexander V. Chernikov 98974b941f0SAlexander V. Chernikov return (0); 99074b941f0SAlexander V. Chernikov } 99174b941f0SAlexander V. Chernikov 992ce2817b5SAlexander V. Chernikov static uint32_t 993ce2817b5SAlexander V. Chernikov hash_ent(struct chashentry *ent, int af, int mlen, uint32_t size) 994ce2817b5SAlexander V. Chernikov { 995ce2817b5SAlexander V. Chernikov uint32_t hash; 996ce2817b5SAlexander V. Chernikov 997ce2817b5SAlexander V. Chernikov if (af == AF_INET) { 998ce2817b5SAlexander V. Chernikov hash = hash_ip(ent->a.a4, size); 999ce2817b5SAlexander V. Chernikov } else { 1000ce2817b5SAlexander V. Chernikov if (mlen == 64) 1001ce2817b5SAlexander V. Chernikov hash = hash_ip64(&ent->a.a6, size); 1002ce2817b5SAlexander V. Chernikov else 1003ce2817b5SAlexander V. Chernikov hash = hash_ip6(&ent->a.a6, size); 1004ce2817b5SAlexander V. Chernikov } 1005ce2817b5SAlexander V. Chernikov 1006ce2817b5SAlexander V. Chernikov return (hash); 1007ce2817b5SAlexander V. Chernikov } 1008ce2817b5SAlexander V. Chernikov 1009ce2817b5SAlexander V. Chernikov static int 1010ce2817b5SAlexander V. Chernikov tei_to_chash_ent(struct tentry_info *tei, struct chashentry *ent) 1011ce2817b5SAlexander V. Chernikov { 1012ce2817b5SAlexander V. Chernikov struct in6_addr mask6; 1013ce2817b5SAlexander V. Chernikov int mlen; 1014ce2817b5SAlexander V. Chernikov 1015ce2817b5SAlexander V. Chernikov 1016ce2817b5SAlexander V. Chernikov mlen = tei->masklen; 1017ce2817b5SAlexander V. Chernikov 1018ce2817b5SAlexander V. Chernikov if (tei->subtype == AF_INET) { 1019ce2817b5SAlexander V. Chernikov #ifdef INET 1020ce2817b5SAlexander V. Chernikov if (mlen > 32) 1021ce2817b5SAlexander V. Chernikov return (EINVAL); 1022ce2817b5SAlexander V. Chernikov ent->type = AF_INET; 1023ce2817b5SAlexander V. Chernikov 1024ce2817b5SAlexander V. Chernikov /* Calculate masked address */ 1025ce2817b5SAlexander V. Chernikov ent->a.a4 = ntohl(*((in_addr_t *)tei->paddr)) >> (32 - mlen); 1026ce2817b5SAlexander V. Chernikov #endif 1027ce2817b5SAlexander V. Chernikov #ifdef INET6 1028ce2817b5SAlexander V. Chernikov } else if (tei->subtype == AF_INET6) { 1029ce2817b5SAlexander V. Chernikov /* IPv6 case */ 1030ce2817b5SAlexander V. Chernikov if (mlen > 128) 1031ce2817b5SAlexander V. Chernikov return (EINVAL); 1032ce2817b5SAlexander V. Chernikov ent->type = AF_INET6; 1033ce2817b5SAlexander V. Chernikov 1034ce2817b5SAlexander V. Chernikov ipv6_writemask(&mask6, mlen); 1035ce2817b5SAlexander V. Chernikov memcpy(&ent->a.a6, tei->paddr, sizeof(struct in6_addr)); 1036ce2817b5SAlexander V. Chernikov APPLY_MASK(&ent->a.a6, &mask6); 1037ce2817b5SAlexander V. Chernikov #endif 1038ce2817b5SAlexander V. Chernikov } else { 1039ce2817b5SAlexander V. Chernikov /* Unknown CIDR type */ 1040ce2817b5SAlexander V. Chernikov return (EINVAL); 1041ce2817b5SAlexander V. Chernikov } 1042ce2817b5SAlexander V. Chernikov ent->value = tei->value; 1043ce2817b5SAlexander V. Chernikov 1044ce2817b5SAlexander V. Chernikov return (0); 1045ce2817b5SAlexander V. Chernikov } 1046ce2817b5SAlexander V. Chernikov 104774b941f0SAlexander V. Chernikov static int 1048914bffb6SAlexander V. Chernikov ta_find_chash_tentry(void *ta_state, struct table_info *ti, 1049914bffb6SAlexander V. Chernikov ipfw_obj_tentry *tent) 105074b941f0SAlexander V. Chernikov { 10510bce0c23SAlexander V. Chernikov struct chash_cfg *cfg; 1052ce2817b5SAlexander V. Chernikov struct chashbhead *head; 1053ce2817b5SAlexander V. Chernikov struct chashentry ent, *tmp; 1054ce2817b5SAlexander V. Chernikov struct tentry_info tei; 1055ce2817b5SAlexander V. Chernikov int error; 1056ce2817b5SAlexander V. Chernikov uint32_t hash; 105774b941f0SAlexander V. Chernikov 10580bce0c23SAlexander V. Chernikov cfg = (struct chash_cfg *)ta_state; 1059ce2817b5SAlexander V. Chernikov 1060ce2817b5SAlexander V. Chernikov memset(&ent, 0, sizeof(ent)); 1061ce2817b5SAlexander V. Chernikov memset(&tei, 0, sizeof(tei)); 1062ce2817b5SAlexander V. Chernikov 1063914bffb6SAlexander V. Chernikov if (tent->subtype == AF_INET) { 1064914bffb6SAlexander V. Chernikov tei.paddr = &tent->k.addr; 10650bce0c23SAlexander V. Chernikov tei.masklen = cfg->mask4; 1066ce2817b5SAlexander V. Chernikov tei.subtype = AF_INET; 106774b941f0SAlexander V. Chernikov 1068ce2817b5SAlexander V. Chernikov if ((error = tei_to_chash_ent(&tei, &ent)) != 0) 1069ce2817b5SAlexander V. Chernikov return (error); 1070ce2817b5SAlexander V. Chernikov 10710bce0c23SAlexander V. Chernikov head = cfg->head4; 10720bce0c23SAlexander V. Chernikov hash = hash_ent(&ent, AF_INET, cfg->mask4, cfg->size4); 1073ce2817b5SAlexander V. Chernikov /* Check for existence */ 1074ce2817b5SAlexander V. Chernikov SLIST_FOREACH(tmp, &head[hash], next) { 1075ce2817b5SAlexander V. Chernikov if (tmp->a.a4 != ent.a.a4) 1076ce2817b5SAlexander V. Chernikov continue; 1077ce2817b5SAlexander V. Chernikov 1078ce2817b5SAlexander V. Chernikov ta_dump_chash_tentry(ta_state, ti, tmp, tent); 107974b941f0SAlexander V. Chernikov return (0); 108074b941f0SAlexander V. Chernikov } 1081ce2817b5SAlexander V. Chernikov } else { 1082914bffb6SAlexander V. Chernikov tei.paddr = &tent->k.addr6; 10830bce0c23SAlexander V. Chernikov tei.masklen = cfg->mask6; 1084ce2817b5SAlexander V. Chernikov tei.subtype = AF_INET6; 1085ce2817b5SAlexander V. Chernikov 1086ce2817b5SAlexander V. Chernikov if ((error = tei_to_chash_ent(&tei, &ent)) != 0) 1087ce2817b5SAlexander V. Chernikov return (error); 1088ce2817b5SAlexander V. Chernikov 10890bce0c23SAlexander V. Chernikov head = cfg->head6; 10900bce0c23SAlexander V. Chernikov hash = hash_ent(&ent, AF_INET6, cfg->mask6, cfg->size6); 1091ce2817b5SAlexander V. Chernikov /* Check for existence */ 1092ce2817b5SAlexander V. Chernikov SLIST_FOREACH(tmp, &head[hash], next) { 1093ce2817b5SAlexander V. Chernikov if (memcmp(&tmp->a.a6, &ent.a.a6, 16) != 0) 1094ce2817b5SAlexander V. Chernikov continue; 1095ce2817b5SAlexander V. Chernikov ta_dump_chash_tentry(ta_state, ti, tmp, tent); 1096ce2817b5SAlexander V. Chernikov return (0); 1097ce2817b5SAlexander V. Chernikov } 1098ce2817b5SAlexander V. Chernikov } 1099ce2817b5SAlexander V. Chernikov 110074b941f0SAlexander V. Chernikov return (ENOENT); 110174b941f0SAlexander V. Chernikov } 110274b941f0SAlexander V. Chernikov 110374b941f0SAlexander V. Chernikov static void 110474b941f0SAlexander V. Chernikov ta_foreach_chash(void *ta_state, struct table_info *ti, ta_foreach_f *f, 110574b941f0SAlexander V. Chernikov void *arg) 110674b941f0SAlexander V. Chernikov { 11070bce0c23SAlexander V. Chernikov struct chash_cfg *cfg; 110874b941f0SAlexander V. Chernikov struct chashentry *ent, *ent_next; 110974b941f0SAlexander V. Chernikov int i; 111074b941f0SAlexander V. Chernikov 11110bce0c23SAlexander V. Chernikov cfg = (struct chash_cfg *)ta_state; 111274b941f0SAlexander V. Chernikov 11130bce0c23SAlexander V. Chernikov for (i = 0; i < cfg->size4; i++) 11140bce0c23SAlexander V. Chernikov SLIST_FOREACH_SAFE(ent, &cfg->head4[i], next, ent_next) 111574b941f0SAlexander V. Chernikov f(ent, arg); 111674b941f0SAlexander V. Chernikov 11170bce0c23SAlexander V. Chernikov for (i = 0; i < cfg->size6; i++) 11180bce0c23SAlexander V. Chernikov SLIST_FOREACH_SAFE(ent, &cfg->head6[i], next, ent_next) 111974b941f0SAlexander V. Chernikov f(ent, arg); 112074b941f0SAlexander V. Chernikov } 112174b941f0SAlexander V. Chernikov 112274b941f0SAlexander V. Chernikov static int 112374b941f0SAlexander V. Chernikov ta_prepare_add_chash(struct ip_fw_chain *ch, struct tentry_info *tei, 112474b941f0SAlexander V. Chernikov void *ta_buf) 112574b941f0SAlexander V. Chernikov { 112674b941f0SAlexander V. Chernikov struct ta_buf_chash *tb; 112774b941f0SAlexander V. Chernikov struct chashentry *ent; 1128ce2817b5SAlexander V. Chernikov int error; 112974b941f0SAlexander V. Chernikov 113074b941f0SAlexander V. Chernikov tb = (struct ta_buf_chash *)ta_buf; 113174b941f0SAlexander V. Chernikov 113274b941f0SAlexander V. Chernikov ent = malloc(sizeof(*ent), M_IPFW_TBL, M_WAITOK | M_ZERO); 113374b941f0SAlexander V. Chernikov 1134ce2817b5SAlexander V. Chernikov error = tei_to_chash_ent(tei, ent); 1135ce2817b5SAlexander V. Chernikov if (error != 0) { 1136ce2817b5SAlexander V. Chernikov free(ent, M_IPFW_TBL); 1137ce2817b5SAlexander V. Chernikov return (error); 113874b941f0SAlexander V. Chernikov } 1139ce2817b5SAlexander V. Chernikov tb->ent_ptr = ent; 114074b941f0SAlexander V. Chernikov 114174b941f0SAlexander V. Chernikov return (0); 114274b941f0SAlexander V. Chernikov } 114374b941f0SAlexander V. Chernikov 114474b941f0SAlexander V. Chernikov static int 114574b941f0SAlexander V. Chernikov ta_add_chash(void *ta_state, struct table_info *ti, struct tentry_info *tei, 1146b6ee846eSAlexander V. Chernikov void *ta_buf, uint32_t *pnum) 114774b941f0SAlexander V. Chernikov { 11480bce0c23SAlexander V. Chernikov struct chash_cfg *cfg; 114974b941f0SAlexander V. Chernikov struct chashbhead *head; 115074b941f0SAlexander V. Chernikov struct chashentry *ent, *tmp; 115174b941f0SAlexander V. Chernikov struct ta_buf_chash *tb; 115274b941f0SAlexander V. Chernikov int exists; 1153648e8380SAlexander V. Chernikov uint32_t hash, value; 115474b941f0SAlexander V. Chernikov 11550bce0c23SAlexander V. Chernikov cfg = (struct chash_cfg *)ta_state; 115674b941f0SAlexander V. Chernikov tb = (struct ta_buf_chash *)ta_buf; 115774b941f0SAlexander V. Chernikov ent = (struct chashentry *)tb->ent_ptr; 115874b941f0SAlexander V. Chernikov hash = 0; 115974b941f0SAlexander V. Chernikov exists = 0; 116074b941f0SAlexander V. Chernikov 116174b941f0SAlexander V. Chernikov if (tei->subtype == AF_INET) { 11620bce0c23SAlexander V. Chernikov if (tei->masklen != cfg->mask4) 116374b941f0SAlexander V. Chernikov return (EINVAL); 11640bce0c23SAlexander V. Chernikov head = cfg->head4; 11650bce0c23SAlexander V. Chernikov hash = hash_ent(ent, AF_INET, cfg->mask4, cfg->size4); 1166ce2817b5SAlexander V. Chernikov 116774b941f0SAlexander V. Chernikov /* Check for existence */ 116874b941f0SAlexander V. Chernikov SLIST_FOREACH(tmp, &head[hash], next) { 116974b941f0SAlexander V. Chernikov if (tmp->a.a4 == ent->a.a4) { 117074b941f0SAlexander V. Chernikov exists = 1; 117174b941f0SAlexander V. Chernikov break; 117274b941f0SAlexander V. Chernikov } 117374b941f0SAlexander V. Chernikov } 117474b941f0SAlexander V. Chernikov } else { 11750bce0c23SAlexander V. Chernikov if (tei->masklen != cfg->mask6) 117674b941f0SAlexander V. Chernikov return (EINVAL); 11770bce0c23SAlexander V. Chernikov head = cfg->head6; 11780bce0c23SAlexander V. Chernikov hash = hash_ent(ent, AF_INET6, cfg->mask6, cfg->size6); 117974b941f0SAlexander V. Chernikov /* Check for existence */ 118074b941f0SAlexander V. Chernikov SLIST_FOREACH(tmp, &head[hash], next) { 1181ce2817b5SAlexander V. Chernikov if (memcmp(&tmp->a.a6, &ent->a.a6, 16) == 0) { 118274b941f0SAlexander V. Chernikov exists = 1; 118374b941f0SAlexander V. Chernikov break; 118474b941f0SAlexander V. Chernikov } 118574b941f0SAlexander V. Chernikov } 118674b941f0SAlexander V. Chernikov } 118774b941f0SAlexander V. Chernikov 118874b941f0SAlexander V. Chernikov if (exists == 1) { 118974b941f0SAlexander V. Chernikov if ((tei->flags & TEI_FLAGS_UPDATE) == 0) 119074b941f0SAlexander V. Chernikov return (EEXIST); 119174b941f0SAlexander V. Chernikov /* Record already exists. Update value if we're asked to */ 1192648e8380SAlexander V. Chernikov value = tmp->value; 119374b941f0SAlexander V. Chernikov tmp->value = tei->value; 1194648e8380SAlexander V. Chernikov tei->value = value; 119574b941f0SAlexander V. Chernikov /* Indicate that update has happened instead of addition */ 119674b941f0SAlexander V. Chernikov tei->flags |= TEI_FLAGS_UPDATED; 119774b941f0SAlexander V. Chernikov *pnum = 0; 119874b941f0SAlexander V. Chernikov } else { 11994c0c07a5SAlexander V. Chernikov if ((tei->flags & TEI_FLAGS_DONTADD) != 0) 12004c0c07a5SAlexander V. Chernikov return (EFBIG); 120174b941f0SAlexander V. Chernikov SLIST_INSERT_HEAD(&head[hash], ent, next); 120274b941f0SAlexander V. Chernikov tb->ent_ptr = NULL; 120374b941f0SAlexander V. Chernikov *pnum = 1; 1204ce2817b5SAlexander V. Chernikov 1205b6ee846eSAlexander V. Chernikov /* Update counters */ 1206b6ee846eSAlexander V. Chernikov if (tei->subtype == AF_INET) 12070bce0c23SAlexander V. Chernikov cfg->items4++; 1208b6ee846eSAlexander V. Chernikov else 12090bce0c23SAlexander V. Chernikov cfg->items6++; 121074b941f0SAlexander V. Chernikov } 121174b941f0SAlexander V. Chernikov 121274b941f0SAlexander V. Chernikov return (0); 121374b941f0SAlexander V. Chernikov } 121474b941f0SAlexander V. Chernikov 121574b941f0SAlexander V. Chernikov static int 121674b941f0SAlexander V. Chernikov ta_prepare_del_chash(struct ip_fw_chain *ch, struct tentry_info *tei, 121774b941f0SAlexander V. Chernikov void *ta_buf) 121874b941f0SAlexander V. Chernikov { 121974b941f0SAlexander V. Chernikov struct ta_buf_chash *tb; 122074b941f0SAlexander V. Chernikov 122174b941f0SAlexander V. Chernikov tb = (struct ta_buf_chash *)ta_buf; 122274b941f0SAlexander V. Chernikov 1223ce2817b5SAlexander V. Chernikov return (tei_to_chash_ent(tei, &tb->ent)); 122474b941f0SAlexander V. Chernikov } 122574b941f0SAlexander V. Chernikov 122674b941f0SAlexander V. Chernikov static int 122774b941f0SAlexander V. Chernikov ta_del_chash(void *ta_state, struct table_info *ti, struct tentry_info *tei, 1228b6ee846eSAlexander V. Chernikov void *ta_buf, uint32_t *pnum) 122974b941f0SAlexander V. Chernikov { 12300bce0c23SAlexander V. Chernikov struct chash_cfg *cfg; 123174b941f0SAlexander V. Chernikov struct chashbhead *head; 12320bce0c23SAlexander V. Chernikov struct chashentry *tmp, *tmp_next, *ent; 123374b941f0SAlexander V. Chernikov struct ta_buf_chash *tb; 123474b941f0SAlexander V. Chernikov uint32_t hash; 123574b941f0SAlexander V. Chernikov 12360bce0c23SAlexander V. Chernikov cfg = (struct chash_cfg *)ta_state; 123774b941f0SAlexander V. Chernikov tb = (struct ta_buf_chash *)ta_buf; 12380bce0c23SAlexander V. Chernikov ent = &tb->ent; 123974b941f0SAlexander V. Chernikov 124074b941f0SAlexander V. Chernikov if (tei->subtype == AF_INET) { 12410bce0c23SAlexander V. Chernikov if (tei->masklen != cfg->mask4) 124274b941f0SAlexander V. Chernikov return (EINVAL); 12430bce0c23SAlexander V. Chernikov head = cfg->head4; 12440bce0c23SAlexander V. Chernikov hash = hash_ent(ent, AF_INET, cfg->mask4, cfg->size4); 124574b941f0SAlexander V. Chernikov 12460bce0c23SAlexander V. Chernikov SLIST_FOREACH_SAFE(tmp, &head[hash], next, tmp_next) { 12470bce0c23SAlexander V. Chernikov if (tmp->a.a4 != ent->a.a4) 1248648e8380SAlexander V. Chernikov continue; 1249648e8380SAlexander V. Chernikov 12500bce0c23SAlexander V. Chernikov SLIST_REMOVE(&head[hash], tmp, chashentry, next); 12510bce0c23SAlexander V. Chernikov cfg->items4--; 12520bce0c23SAlexander V. Chernikov tb->ent_ptr = tmp; 12530bce0c23SAlexander V. Chernikov tei->value = tmp->value; 1254648e8380SAlexander V. Chernikov *pnum = 1; 125574b941f0SAlexander V. Chernikov return (0); 125674b941f0SAlexander V. Chernikov } 125774b941f0SAlexander V. Chernikov } else { 12580bce0c23SAlexander V. Chernikov if (tei->masklen != cfg->mask6) 125974b941f0SAlexander V. Chernikov return (EINVAL); 12600bce0c23SAlexander V. Chernikov head = cfg->head6; 12610bce0c23SAlexander V. Chernikov hash = hash_ent(ent, AF_INET6, cfg->mask6, cfg->size6); 12620bce0c23SAlexander V. Chernikov SLIST_FOREACH_SAFE(tmp, &head[hash], next, tmp_next) { 12630bce0c23SAlexander V. Chernikov if (memcmp(&tmp->a.a6, &ent->a.a6, 16) != 0) 1264648e8380SAlexander V. Chernikov continue; 1265648e8380SAlexander V. Chernikov 12660bce0c23SAlexander V. Chernikov SLIST_REMOVE(&head[hash], tmp, chashentry, next); 12670bce0c23SAlexander V. Chernikov cfg->items6--; 12680bce0c23SAlexander V. Chernikov tb->ent_ptr = tmp; 12690bce0c23SAlexander V. Chernikov tei->value = tmp->value; 127074b941f0SAlexander V. Chernikov *pnum = 1; 127174b941f0SAlexander V. Chernikov return (0); 127274b941f0SAlexander V. Chernikov } 127374b941f0SAlexander V. Chernikov } 127474b941f0SAlexander V. Chernikov 127574b941f0SAlexander V. Chernikov return (ENOENT); 127674b941f0SAlexander V. Chernikov } 127774b941f0SAlexander V. Chernikov 127874b941f0SAlexander V. Chernikov static void 127974b941f0SAlexander V. Chernikov ta_flush_chash_entry(struct ip_fw_chain *ch, struct tentry_info *tei, 128074b941f0SAlexander V. Chernikov void *ta_buf) 128174b941f0SAlexander V. Chernikov { 128274b941f0SAlexander V. Chernikov struct ta_buf_chash *tb; 128374b941f0SAlexander V. Chernikov 128474b941f0SAlexander V. Chernikov tb = (struct ta_buf_chash *)ta_buf; 128574b941f0SAlexander V. Chernikov 128674b941f0SAlexander V. Chernikov if (tb->ent_ptr != NULL) 128774b941f0SAlexander V. Chernikov free(tb->ent_ptr, M_IPFW_TBL); 128874b941f0SAlexander V. Chernikov } 128974b941f0SAlexander V. Chernikov 1290ce2817b5SAlexander V. Chernikov /* 1291ce2817b5SAlexander V. Chernikov * Hash growing callbacks. 1292ce2817b5SAlexander V. Chernikov */ 1293ce2817b5SAlexander V. Chernikov 1294b6ee846eSAlexander V. Chernikov static int 1295b6ee846eSAlexander V. Chernikov ta_has_space_chash(void *ta_state, struct table_info *ti, uint32_t count, 1296b6ee846eSAlexander V. Chernikov uint64_t *pflags) 1297b6ee846eSAlexander V. Chernikov { 1298b6ee846eSAlexander V. Chernikov struct chash_cfg *cfg; 1299b6ee846eSAlexander V. Chernikov uint64_t data; 1300b6ee846eSAlexander V. Chernikov 1301b6ee846eSAlexander V. Chernikov /* 1302b6ee846eSAlexander V. Chernikov * Since we don't know exact number of IPv4/IPv6 records in @count, 1303b6ee846eSAlexander V. Chernikov * ignore non-zero @count value at all. Check current hash sizes 1304b6ee846eSAlexander V. Chernikov * and return appropriate data. 1305b6ee846eSAlexander V. Chernikov */ 1306b6ee846eSAlexander V. Chernikov 1307b6ee846eSAlexander V. Chernikov cfg = (struct chash_cfg *)ta_state; 1308b6ee846eSAlexander V. Chernikov 1309b6ee846eSAlexander V. Chernikov data = 0; 1310b6ee846eSAlexander V. Chernikov if (cfg->items4 > cfg->size4 && cfg->size4 < 65536) 1311b6ee846eSAlexander V. Chernikov data |= (cfg->size4 * 2) << 16; 1312b6ee846eSAlexander V. Chernikov if (cfg->items6 > cfg->size6 && cfg->size6 < 65536) 1313b6ee846eSAlexander V. Chernikov data |= cfg->size6 * 2; 1314b6ee846eSAlexander V. Chernikov 1315b6ee846eSAlexander V. Chernikov if (data != 0) { 1316b6ee846eSAlexander V. Chernikov *pflags = data; 1317b6ee846eSAlexander V. Chernikov return (0); 1318b6ee846eSAlexander V. Chernikov } 1319b6ee846eSAlexander V. Chernikov 1320b6ee846eSAlexander V. Chernikov return (1); 1321b6ee846eSAlexander V. Chernikov } 1322b6ee846eSAlexander V. Chernikov 1323ce2817b5SAlexander V. Chernikov /* 1324ce2817b5SAlexander V. Chernikov * Allocate new, larger chash. 1325ce2817b5SAlexander V. Chernikov */ 1326ce2817b5SAlexander V. Chernikov static int 1327ce2817b5SAlexander V. Chernikov ta_prepare_mod_chash(void *ta_buf, uint64_t *pflags) 1328ce2817b5SAlexander V. Chernikov { 1329ce2817b5SAlexander V. Chernikov struct mod_item *mi; 1330ce2817b5SAlexander V. Chernikov struct chashbhead *head; 1331ce2817b5SAlexander V. Chernikov int i; 1332ce2817b5SAlexander V. Chernikov 1333ce2817b5SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 1334ce2817b5SAlexander V. Chernikov 1335ce2817b5SAlexander V. Chernikov memset(mi, 0, sizeof(struct mod_item)); 1336b6ee846eSAlexander V. Chernikov mi->size = (*pflags >> 16) & 0xFFFF; 1337b6ee846eSAlexander V. Chernikov mi->size6 = *pflags & 0xFFFF; 1338b6ee846eSAlexander V. Chernikov if (mi->size > 0) { 1339b6ee846eSAlexander V. Chernikov head = malloc(sizeof(struct chashbhead) * mi->size, 1340b6ee846eSAlexander V. Chernikov M_IPFW, M_WAITOK | M_ZERO); 1341ce2817b5SAlexander V. Chernikov for (i = 0; i < mi->size; i++) 1342ce2817b5SAlexander V. Chernikov SLIST_INIT(&head[i]); 1343ce2817b5SAlexander V. Chernikov mi->main_ptr = head; 1344b6ee846eSAlexander V. Chernikov } 1345b6ee846eSAlexander V. Chernikov 1346b6ee846eSAlexander V. Chernikov if (mi->size6 > 0) { 1347b6ee846eSAlexander V. Chernikov head = malloc(sizeof(struct chashbhead) * mi->size6, 1348b6ee846eSAlexander V. Chernikov M_IPFW, M_WAITOK | M_ZERO); 1349b6ee846eSAlexander V. Chernikov for (i = 0; i < mi->size6; i++) 1350b6ee846eSAlexander V. Chernikov SLIST_INIT(&head[i]); 1351b6ee846eSAlexander V. Chernikov mi->main_ptr6 = head; 1352b6ee846eSAlexander V. Chernikov } 1353ce2817b5SAlexander V. Chernikov 1354ce2817b5SAlexander V. Chernikov return (0); 1355ce2817b5SAlexander V. Chernikov } 1356ce2817b5SAlexander V. Chernikov 1357ce2817b5SAlexander V. Chernikov /* 1358ce2817b5SAlexander V. Chernikov * Copy data from old runtime array to new one. 1359ce2817b5SAlexander V. Chernikov */ 1360ce2817b5SAlexander V. Chernikov static int 1361ce2817b5SAlexander V. Chernikov ta_fill_mod_chash(void *ta_state, struct table_info *ti, void *ta_buf, 1362ce2817b5SAlexander V. Chernikov uint64_t *pflags) 1363ce2817b5SAlexander V. Chernikov { 1364ce2817b5SAlexander V. Chernikov 1365ce2817b5SAlexander V. Chernikov /* In is not possible to do rehash if we're not holidng WLOCK. */ 1366ce2817b5SAlexander V. Chernikov return (0); 1367ce2817b5SAlexander V. Chernikov } 1368ce2817b5SAlexander V. Chernikov 1369ce2817b5SAlexander V. Chernikov /* 1370ce2817b5SAlexander V. Chernikov * Switch old & new arrays. 1371ce2817b5SAlexander V. Chernikov */ 1372ce2817b5SAlexander V. Chernikov static int 1373ce2817b5SAlexander V. Chernikov ta_modify_chash(void *ta_state, struct table_info *ti, void *ta_buf, 1374ce2817b5SAlexander V. Chernikov uint64_t pflags) 1375ce2817b5SAlexander V. Chernikov { 1376ce2817b5SAlexander V. Chernikov struct mod_item *mi; 1377b6ee846eSAlexander V. Chernikov struct chash_cfg *cfg; 1378ce2817b5SAlexander V. Chernikov struct chashbhead *old_head, *new_head; 1379ce2817b5SAlexander V. Chernikov struct chashentry *ent, *ent_next; 1380ce2817b5SAlexander V. Chernikov int af, i, mlen; 1381ce2817b5SAlexander V. Chernikov uint32_t nhash; 1382b6ee846eSAlexander V. Chernikov size_t old_size, new_size; 1383ce2817b5SAlexander V. Chernikov 1384ce2817b5SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 1385b6ee846eSAlexander V. Chernikov cfg = (struct chash_cfg *)ta_state; 1386ce2817b5SAlexander V. Chernikov 1387ce2817b5SAlexander V. Chernikov /* Check which hash we need to grow and do we still need that */ 1388b6ee846eSAlexander V. Chernikov if (mi->size > 0 && cfg->size4 < mi->size) { 1389ce2817b5SAlexander V. Chernikov new_head = (struct chashbhead *)mi->main_ptr; 1390b6ee846eSAlexander V. Chernikov new_size = mi->size; 1391b6ee846eSAlexander V. Chernikov old_size = cfg->size4; 1392b6ee846eSAlexander V. Chernikov old_head = ti->state; 1393b6ee846eSAlexander V. Chernikov mlen = cfg->mask4; 1394b6ee846eSAlexander V. Chernikov af = AF_INET; 1395b6ee846eSAlexander V. Chernikov 1396ce2817b5SAlexander V. Chernikov for (i = 0; i < old_size; i++) { 1397ce2817b5SAlexander V. Chernikov SLIST_FOREACH_SAFE(ent, &old_head[i], next, ent_next) { 1398b6ee846eSAlexander V. Chernikov nhash = hash_ent(ent, af, mlen, new_size); 1399ce2817b5SAlexander V. Chernikov SLIST_INSERT_HEAD(&new_head[nhash], ent, next); 1400ce2817b5SAlexander V. Chernikov } 1401ce2817b5SAlexander V. Chernikov } 1402ce2817b5SAlexander V. Chernikov 1403ce2817b5SAlexander V. Chernikov ti->state = new_head; 1404b6ee846eSAlexander V. Chernikov cfg->head4 = new_head; 1405b6ee846eSAlexander V. Chernikov cfg->size4 = mi->size; 1406b6ee846eSAlexander V. Chernikov mi->main_ptr = old_head; 1407ce2817b5SAlexander V. Chernikov } 1408ce2817b5SAlexander V. Chernikov 1409b6ee846eSAlexander V. Chernikov if (mi->size6 > 0 && cfg->size6 < mi->size6) { 1410b6ee846eSAlexander V. Chernikov new_head = (struct chashbhead *)mi->main_ptr6; 1411b6ee846eSAlexander V. Chernikov new_size = mi->size6; 1412b6ee846eSAlexander V. Chernikov old_size = cfg->size6; 1413b6ee846eSAlexander V. Chernikov old_head = ti->xstate; 1414b6ee846eSAlexander V. Chernikov mlen = cfg->mask6; 1415b6ee846eSAlexander V. Chernikov af = AF_INET6; 1416914bffb6SAlexander V. Chernikov 1417b6ee846eSAlexander V. Chernikov for (i = 0; i < old_size; i++) { 1418b6ee846eSAlexander V. Chernikov SLIST_FOREACH_SAFE(ent, &old_head[i], next, ent_next) { 1419b6ee846eSAlexander V. Chernikov nhash = hash_ent(ent, af, mlen, new_size); 1420b6ee846eSAlexander V. Chernikov SLIST_INSERT_HEAD(&new_head[nhash], ent, next); 1421b6ee846eSAlexander V. Chernikov } 1422b6ee846eSAlexander V. Chernikov } 1423b6ee846eSAlexander V. Chernikov 1424b6ee846eSAlexander V. Chernikov ti->xstate = new_head; 1425b6ee846eSAlexander V. Chernikov cfg->head6 = new_head; 1426b6ee846eSAlexander V. Chernikov cfg->size6 = mi->size6; 1427b6ee846eSAlexander V. Chernikov mi->main_ptr6 = old_head; 1428b6ee846eSAlexander V. Chernikov } 1429b6ee846eSAlexander V. Chernikov 1430b6ee846eSAlexander V. Chernikov /* Update lower 32 bits with new values */ 1431b6ee846eSAlexander V. Chernikov ti->data &= 0xFFFFFFFF00000000; 1432b6ee846eSAlexander V. Chernikov ti->data |= log2(cfg->size4) << 8 | log2(cfg->size6); 1433ce2817b5SAlexander V. Chernikov 1434ce2817b5SAlexander V. Chernikov return (0); 1435ce2817b5SAlexander V. Chernikov } 1436ce2817b5SAlexander V. Chernikov 1437ce2817b5SAlexander V. Chernikov /* 1438ce2817b5SAlexander V. Chernikov * Free unneded array. 1439ce2817b5SAlexander V. Chernikov */ 1440ce2817b5SAlexander V. Chernikov static void 1441ce2817b5SAlexander V. Chernikov ta_flush_mod_chash(void *ta_buf) 1442ce2817b5SAlexander V. Chernikov { 1443ce2817b5SAlexander V. Chernikov struct mod_item *mi; 1444ce2817b5SAlexander V. Chernikov 1445ce2817b5SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 1446ce2817b5SAlexander V. Chernikov if (mi->main_ptr != NULL) 1447ce2817b5SAlexander V. Chernikov free(mi->main_ptr, M_IPFW); 1448b6ee846eSAlexander V. Chernikov if (mi->main_ptr6 != NULL) 1449b6ee846eSAlexander V. Chernikov free(mi->main_ptr6, M_IPFW); 1450ce2817b5SAlexander V. Chernikov } 1451ce2817b5SAlexander V. Chernikov 145274b941f0SAlexander V. Chernikov struct table_algo cidr_hash = { 145374b941f0SAlexander V. Chernikov .name = "cidr:hash", 14549d099b4fSAlexander V. Chernikov .type = IPFW_TABLE_CIDR, 145557a1cf95SAlexander V. Chernikov .ta_buf_size = sizeof(struct ta_buf_chash), 145674b941f0SAlexander V. Chernikov .init = ta_init_chash, 145774b941f0SAlexander V. Chernikov .destroy = ta_destroy_chash, 145874b941f0SAlexander V. Chernikov .prepare_add = ta_prepare_add_chash, 145974b941f0SAlexander V. Chernikov .prepare_del = ta_prepare_del_chash, 146074b941f0SAlexander V. Chernikov .add = ta_add_chash, 146174b941f0SAlexander V. Chernikov .del = ta_del_chash, 146274b941f0SAlexander V. Chernikov .flush_entry = ta_flush_chash_entry, 146374b941f0SAlexander V. Chernikov .foreach = ta_foreach_chash, 146474b941f0SAlexander V. Chernikov .dump_tentry = ta_dump_chash_tentry, 146574b941f0SAlexander V. Chernikov .find_tentry = ta_find_chash_tentry, 146674b941f0SAlexander V. Chernikov .print_config = ta_print_chash_config, 1467b6ee846eSAlexander V. Chernikov .has_space = ta_has_space_chash, 1468ce2817b5SAlexander V. Chernikov .prepare_mod = ta_prepare_mod_chash, 1469ce2817b5SAlexander V. Chernikov .fill_mod = ta_fill_mod_chash, 1470ce2817b5SAlexander V. Chernikov .modify = ta_modify_chash, 1471ce2817b5SAlexander V. Chernikov .flush_mod = ta_flush_mod_chash, 147274b941f0SAlexander V. Chernikov }; 147374b941f0SAlexander V. Chernikov 147474b941f0SAlexander V. Chernikov 147574b941f0SAlexander V. Chernikov /* 147668394ec8SAlexander V. Chernikov * Iface table cmds. 147768394ec8SAlexander V. Chernikov * 147868394ec8SAlexander V. Chernikov * Implementation: 147968394ec8SAlexander V. Chernikov * 148068394ec8SAlexander V. Chernikov * Runtime part: 148168394ec8SAlexander V. Chernikov * - sorted array of "struct ifidx" pointed by ti->state. 1482b23d5de9SAlexander V. Chernikov * Array is allocated with rounding up to IFIDX_CHUNK. Only existing 148368394ec8SAlexander V. Chernikov * interfaces are stored in array, however its allocated size is 148468394ec8SAlexander V. Chernikov * sufficient to hold all table records if needed. 148568394ec8SAlexander V. Chernikov * - current array size is stored in ti->data 148668394ec8SAlexander V. Chernikov * 148768394ec8SAlexander V. Chernikov * Table data: 148868394ec8SAlexander V. Chernikov * - "struct iftable_cfg" is allocated to store table state (ta_state). 148968394ec8SAlexander V. Chernikov * - All table records are stored inside namedobj instance. 14909f7d47b0SAlexander V. Chernikov * 14919f7d47b0SAlexander V. Chernikov */ 14929f7d47b0SAlexander V. Chernikov 149368394ec8SAlexander V. Chernikov struct ifidx { 149468394ec8SAlexander V. Chernikov uint16_t kidx; 149568394ec8SAlexander V. Chernikov uint16_t spare; 149668394ec8SAlexander V. Chernikov uint32_t value; 149768394ec8SAlexander V. Chernikov }; 149868394ec8SAlexander V. Chernikov 149968394ec8SAlexander V. Chernikov struct iftable_cfg; 150068394ec8SAlexander V. Chernikov 150168394ec8SAlexander V. Chernikov struct ifentry { 150268394ec8SAlexander V. Chernikov struct named_object no; 150368394ec8SAlexander V. Chernikov struct ipfw_ifc ic; 150468394ec8SAlexander V. Chernikov struct iftable_cfg *icfg; 150568394ec8SAlexander V. Chernikov uint32_t value; 150668394ec8SAlexander V. Chernikov int linked; 150768394ec8SAlexander V. Chernikov }; 150868394ec8SAlexander V. Chernikov 150968394ec8SAlexander V. Chernikov struct iftable_cfg { 151068394ec8SAlexander V. Chernikov struct namedobj_instance *ii; 151168394ec8SAlexander V. Chernikov struct ip_fw_chain *ch; 151268394ec8SAlexander V. Chernikov struct table_info *ti; 151368394ec8SAlexander V. Chernikov void *main_ptr; 151468394ec8SAlexander V. Chernikov size_t size; /* Number of items allocated in array */ 151568394ec8SAlexander V. Chernikov size_t count; /* Number of all items */ 151668394ec8SAlexander V. Chernikov size_t used; /* Number of items _active_ now */ 151768394ec8SAlexander V. Chernikov }; 151868394ec8SAlexander V. Chernikov 15190bce0c23SAlexander V. Chernikov struct ta_buf_ifidx 15200bce0c23SAlexander V. Chernikov { 15210bce0c23SAlexander V. Chernikov struct ifentry *ife; 15220bce0c23SAlexander V. Chernikov uint32_t value; 15230bce0c23SAlexander V. Chernikov }; 152468394ec8SAlexander V. Chernikov 152568394ec8SAlexander V. Chernikov int compare_ifidx(const void *k, const void *v); 152668394ec8SAlexander V. Chernikov static void if_notifier(struct ip_fw_chain *ch, void *cbdata, uint16_t ifindex); 152768394ec8SAlexander V. Chernikov 152868394ec8SAlexander V. Chernikov int 152968394ec8SAlexander V. Chernikov compare_ifidx(const void *k, const void *v) 153068394ec8SAlexander V. Chernikov { 153168394ec8SAlexander V. Chernikov struct ifidx *ifidx; 153268394ec8SAlexander V. Chernikov uint16_t key; 153368394ec8SAlexander V. Chernikov 153468394ec8SAlexander V. Chernikov key = *((uint16_t *)k); 153568394ec8SAlexander V. Chernikov ifidx = (struct ifidx *)v; 153668394ec8SAlexander V. Chernikov 153768394ec8SAlexander V. Chernikov if (key < ifidx->kidx) 153868394ec8SAlexander V. Chernikov return (-1); 153968394ec8SAlexander V. Chernikov else if (key > ifidx->kidx) 154068394ec8SAlexander V. Chernikov return (1); 154168394ec8SAlexander V. Chernikov 154268394ec8SAlexander V. Chernikov return (0); 154368394ec8SAlexander V. Chernikov } 154468394ec8SAlexander V. Chernikov 154568394ec8SAlexander V. Chernikov /* 154668394ec8SAlexander V. Chernikov * Adds item @item with key @key into ascending-sorted array @base. 154768394ec8SAlexander V. Chernikov * Assumes @base has enough additional storage. 154868394ec8SAlexander V. Chernikov * 154968394ec8SAlexander V. Chernikov * Returns 1 on success, 0 on duplicate key. 155068394ec8SAlexander V. Chernikov */ 15519f7d47b0SAlexander V. Chernikov static int 155268394ec8SAlexander V. Chernikov badd(const void *key, void *item, void *base, size_t nmemb, 155368394ec8SAlexander V. Chernikov size_t size, int (*compar) (const void *, const void *)) 155468394ec8SAlexander V. Chernikov { 155568394ec8SAlexander V. Chernikov int min, max, mid, shift, res; 155668394ec8SAlexander V. Chernikov caddr_t paddr; 155768394ec8SAlexander V. Chernikov 155868394ec8SAlexander V. Chernikov if (nmemb == 0) { 155968394ec8SAlexander V. Chernikov memcpy(base, item, size); 156068394ec8SAlexander V. Chernikov return (1); 156168394ec8SAlexander V. Chernikov } 156268394ec8SAlexander V. Chernikov 156368394ec8SAlexander V. Chernikov /* Binary search */ 156468394ec8SAlexander V. Chernikov min = 0; 156568394ec8SAlexander V. Chernikov max = nmemb - 1; 156668394ec8SAlexander V. Chernikov mid = 0; 156768394ec8SAlexander V. Chernikov while (min <= max) { 156868394ec8SAlexander V. Chernikov mid = (min + max) / 2; 156968394ec8SAlexander V. Chernikov res = compar(key, (const void *)((caddr_t)base + mid * size)); 157068394ec8SAlexander V. Chernikov if (res == 0) 157168394ec8SAlexander V. Chernikov return (0); 157268394ec8SAlexander V. Chernikov 157368394ec8SAlexander V. Chernikov if (res > 0) 157468394ec8SAlexander V. Chernikov min = mid + 1; 157568394ec8SAlexander V. Chernikov else 157668394ec8SAlexander V. Chernikov max = mid - 1; 157768394ec8SAlexander V. Chernikov } 157868394ec8SAlexander V. Chernikov 157968394ec8SAlexander V. Chernikov /* Item not found. */ 158068394ec8SAlexander V. Chernikov res = compar(key, (const void *)((caddr_t)base + mid * size)); 158168394ec8SAlexander V. Chernikov if (res > 0) 158268394ec8SAlexander V. Chernikov shift = mid + 1; 158368394ec8SAlexander V. Chernikov else 158468394ec8SAlexander V. Chernikov shift = mid; 158568394ec8SAlexander V. Chernikov 158668394ec8SAlexander V. Chernikov paddr = (caddr_t)base + shift * size; 158768394ec8SAlexander V. Chernikov if (nmemb > shift) 158868394ec8SAlexander V. Chernikov memmove(paddr + size, paddr, (nmemb - shift) * size); 158968394ec8SAlexander V. Chernikov 159068394ec8SAlexander V. Chernikov memcpy(paddr, item, size); 159168394ec8SAlexander V. Chernikov 159268394ec8SAlexander V. Chernikov return (1); 159368394ec8SAlexander V. Chernikov } 159468394ec8SAlexander V. Chernikov 159568394ec8SAlexander V. Chernikov /* 159668394ec8SAlexander V. Chernikov * Deletes item with key @key from ascending-sorted array @base. 159768394ec8SAlexander V. Chernikov * 159868394ec8SAlexander V. Chernikov * Returns 1 on success, 0 for non-existent key. 159968394ec8SAlexander V. Chernikov */ 160068394ec8SAlexander V. Chernikov static int 160168394ec8SAlexander V. Chernikov bdel(const void *key, void *base, size_t nmemb, size_t size, 160268394ec8SAlexander V. Chernikov int (*compar) (const void *, const void *)) 160368394ec8SAlexander V. Chernikov { 160468394ec8SAlexander V. Chernikov caddr_t item; 160568394ec8SAlexander V. Chernikov size_t sz; 160668394ec8SAlexander V. Chernikov 160768394ec8SAlexander V. Chernikov item = (caddr_t)bsearch(key, base, nmemb, size, compar); 160868394ec8SAlexander V. Chernikov 160968394ec8SAlexander V. Chernikov if (item == NULL) 161068394ec8SAlexander V. Chernikov return (0); 161168394ec8SAlexander V. Chernikov 161268394ec8SAlexander V. Chernikov sz = (caddr_t)base + nmemb * size - item; 161368394ec8SAlexander V. Chernikov 161468394ec8SAlexander V. Chernikov if (sz > 0) 161568394ec8SAlexander V. Chernikov memmove(item, item + size, sz); 161668394ec8SAlexander V. Chernikov 161768394ec8SAlexander V. Chernikov return (1); 161868394ec8SAlexander V. Chernikov } 161968394ec8SAlexander V. Chernikov 162068394ec8SAlexander V. Chernikov static struct ifidx * 162168394ec8SAlexander V. Chernikov ifidx_find(struct table_info *ti, void *key) 162268394ec8SAlexander V. Chernikov { 162368394ec8SAlexander V. Chernikov struct ifidx *ifi; 162468394ec8SAlexander V. Chernikov 162568394ec8SAlexander V. Chernikov ifi = bsearch(key, ti->state, ti->data, sizeof(struct ifidx), 162668394ec8SAlexander V. Chernikov compare_ifidx); 162768394ec8SAlexander V. Chernikov 162868394ec8SAlexander V. Chernikov return (ifi); 162968394ec8SAlexander V. Chernikov } 163068394ec8SAlexander V. Chernikov 163168394ec8SAlexander V. Chernikov static int 163268394ec8SAlexander V. Chernikov ta_lookup_ifidx(struct table_info *ti, void *key, uint32_t keylen, 16339f7d47b0SAlexander V. Chernikov uint32_t *val) 16349f7d47b0SAlexander V. Chernikov { 163568394ec8SAlexander V. Chernikov struct ifidx *ifi; 16369f7d47b0SAlexander V. Chernikov 163768394ec8SAlexander V. Chernikov ifi = ifidx_find(ti, key); 16389f7d47b0SAlexander V. Chernikov 163968394ec8SAlexander V. Chernikov if (ifi != NULL) { 164068394ec8SAlexander V. Chernikov *val = ifi->value; 16419f7d47b0SAlexander V. Chernikov return (1); 16429f7d47b0SAlexander V. Chernikov } 16439f7d47b0SAlexander V. Chernikov 16449f7d47b0SAlexander V. Chernikov return (0); 16459f7d47b0SAlexander V. Chernikov } 16469f7d47b0SAlexander V. Chernikov 16479f7d47b0SAlexander V. Chernikov static int 164868394ec8SAlexander V. Chernikov ta_init_ifidx(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti, 1649914bffb6SAlexander V. Chernikov char *data, uint8_t tflags) 16509f7d47b0SAlexander V. Chernikov { 165168394ec8SAlexander V. Chernikov struct iftable_cfg *icfg; 16529f7d47b0SAlexander V. Chernikov 165368394ec8SAlexander V. Chernikov icfg = malloc(sizeof(struct iftable_cfg), M_IPFW, M_WAITOK | M_ZERO); 16549f7d47b0SAlexander V. Chernikov 165568394ec8SAlexander V. Chernikov icfg->ii = ipfw_objhash_create(16); 16560bce0c23SAlexander V. Chernikov icfg->size = 16; 16570bce0c23SAlexander V. Chernikov icfg->main_ptr = malloc(sizeof(struct ifidx) * icfg->size, M_IPFW, 165868394ec8SAlexander V. Chernikov M_WAITOK | M_ZERO); 165968394ec8SAlexander V. Chernikov icfg->ch = ch; 16609f7d47b0SAlexander V. Chernikov 166168394ec8SAlexander V. Chernikov *ta_state = icfg; 166268394ec8SAlexander V. Chernikov ti->state = icfg->main_ptr; 166368394ec8SAlexander V. Chernikov ti->lookup = ta_lookup_ifidx; 16649f7d47b0SAlexander V. Chernikov 16659f7d47b0SAlexander V. Chernikov return (0); 16669f7d47b0SAlexander V. Chernikov } 16679f7d47b0SAlexander V. Chernikov 166868394ec8SAlexander V. Chernikov /* 166968394ec8SAlexander V. Chernikov * Handle tableinfo @ti pointer change (on table array resize). 167068394ec8SAlexander V. Chernikov */ 167168394ec8SAlexander V. Chernikov static void 167268394ec8SAlexander V. Chernikov ta_change_ti_ifidx(void *ta_state, struct table_info *ti) 167368394ec8SAlexander V. Chernikov { 167468394ec8SAlexander V. Chernikov struct iftable_cfg *icfg; 167568394ec8SAlexander V. Chernikov 167668394ec8SAlexander V. Chernikov icfg = (struct iftable_cfg *)ta_state; 167768394ec8SAlexander V. Chernikov icfg->ti = ti; 167868394ec8SAlexander V. Chernikov } 16799f7d47b0SAlexander V. Chernikov 16809f7d47b0SAlexander V. Chernikov static void 168168394ec8SAlexander V. Chernikov destroy_ifidx_locked(struct namedobj_instance *ii, struct named_object *no, 168268394ec8SAlexander V. Chernikov void *arg) 16839f7d47b0SAlexander V. Chernikov { 168468394ec8SAlexander V. Chernikov struct ifentry *ife; 168568394ec8SAlexander V. Chernikov struct ip_fw_chain *ch; 16869f7d47b0SAlexander V. Chernikov 168768394ec8SAlexander V. Chernikov ch = (struct ip_fw_chain *)arg; 168868394ec8SAlexander V. Chernikov ife = (struct ifentry *)no; 168968394ec8SAlexander V. Chernikov 169068394ec8SAlexander V. Chernikov ipfw_iface_del_notify(ch, &ife->ic); 169168394ec8SAlexander V. Chernikov free(ife, M_IPFW_TBL); 16929f7d47b0SAlexander V. Chernikov } 16939f7d47b0SAlexander V. Chernikov 169468394ec8SAlexander V. Chernikov 169568394ec8SAlexander V. Chernikov /* 169668394ec8SAlexander V. Chernikov * Destroys table @ti 169768394ec8SAlexander V. Chernikov */ 169868394ec8SAlexander V. Chernikov static void 169968394ec8SAlexander V. Chernikov ta_destroy_ifidx(void *ta_state, struct table_info *ti) 17009f7d47b0SAlexander V. Chernikov { 170168394ec8SAlexander V. Chernikov struct iftable_cfg *icfg; 170268394ec8SAlexander V. Chernikov struct ip_fw_chain *ch; 170368394ec8SAlexander V. Chernikov 170468394ec8SAlexander V. Chernikov icfg = (struct iftable_cfg *)ta_state; 170568394ec8SAlexander V. Chernikov ch = icfg->ch; 170668394ec8SAlexander V. Chernikov 170768394ec8SAlexander V. Chernikov if (icfg->main_ptr != NULL) 170868394ec8SAlexander V. Chernikov free(icfg->main_ptr, M_IPFW); 170968394ec8SAlexander V. Chernikov 171068394ec8SAlexander V. Chernikov ipfw_objhash_foreach(icfg->ii, destroy_ifidx_locked, ch); 171168394ec8SAlexander V. Chernikov 171268394ec8SAlexander V. Chernikov ipfw_objhash_destroy(icfg->ii); 171368394ec8SAlexander V. Chernikov 171468394ec8SAlexander V. Chernikov free(icfg, M_IPFW); 171568394ec8SAlexander V. Chernikov } 171668394ec8SAlexander V. Chernikov 171768394ec8SAlexander V. Chernikov /* 171868394ec8SAlexander V. Chernikov * Prepare state to add to the table: 171968394ec8SAlexander V. Chernikov * allocate ifentry and reference needed interface. 172068394ec8SAlexander V. Chernikov */ 17219f7d47b0SAlexander V. Chernikov static int 172268394ec8SAlexander V. Chernikov ta_prepare_add_ifidx(struct ip_fw_chain *ch, struct tentry_info *tei, 172368394ec8SAlexander V. Chernikov void *ta_buf) 172468394ec8SAlexander V. Chernikov { 172568394ec8SAlexander V. Chernikov struct ta_buf_ifidx *tb; 172668394ec8SAlexander V. Chernikov char *ifname; 172768394ec8SAlexander V. Chernikov struct ifentry *ife; 172868394ec8SAlexander V. Chernikov 172968394ec8SAlexander V. Chernikov tb = (struct ta_buf_ifidx *)ta_buf; 173068394ec8SAlexander V. Chernikov 173168394ec8SAlexander V. Chernikov /* Check if string is terminated */ 173268394ec8SAlexander V. Chernikov ifname = (char *)tei->paddr; 173368394ec8SAlexander V. Chernikov if (strnlen(ifname, IF_NAMESIZE) == IF_NAMESIZE) 173468394ec8SAlexander V. Chernikov return (EINVAL); 173568394ec8SAlexander V. Chernikov 173668394ec8SAlexander V. Chernikov ife = malloc(sizeof(struct ifentry), M_IPFW_TBL, M_WAITOK | M_ZERO); 173768394ec8SAlexander V. Chernikov ife->value = tei->value; 173868394ec8SAlexander V. Chernikov ife->ic.cb = if_notifier; 173968394ec8SAlexander V. Chernikov ife->ic.cbdata = ife; 174068394ec8SAlexander V. Chernikov 174168394ec8SAlexander V. Chernikov if (ipfw_iface_ref(ch, ifname, &ife->ic) != 0) 174268394ec8SAlexander V. Chernikov return (EINVAL); 174368394ec8SAlexander V. Chernikov 174468394ec8SAlexander V. Chernikov /* Use ipfw_iface 'ifname' field as stable storage */ 174568394ec8SAlexander V. Chernikov ife->no.name = ife->ic.iface->ifname; 174668394ec8SAlexander V. Chernikov 174768394ec8SAlexander V. Chernikov tb->ife = ife; 174868394ec8SAlexander V. Chernikov 174968394ec8SAlexander V. Chernikov return (0); 175068394ec8SAlexander V. Chernikov } 175168394ec8SAlexander V. Chernikov 175268394ec8SAlexander V. Chernikov static int 1753adea6201SAlexander V. Chernikov ta_add_ifidx(void *ta_state, struct table_info *ti, struct tentry_info *tei, 1754b6ee846eSAlexander V. Chernikov void *ta_buf, uint32_t *pnum) 175568394ec8SAlexander V. Chernikov { 175668394ec8SAlexander V. Chernikov struct iftable_cfg *icfg; 175768394ec8SAlexander V. Chernikov struct ifentry *ife, *tmp; 175868394ec8SAlexander V. Chernikov struct ta_buf_ifidx *tb; 175968394ec8SAlexander V. Chernikov struct ipfw_iface *iif; 176068394ec8SAlexander V. Chernikov struct ifidx *ifi; 176168394ec8SAlexander V. Chernikov char *ifname; 1762648e8380SAlexander V. Chernikov uint32_t value; 176368394ec8SAlexander V. Chernikov 176468394ec8SAlexander V. Chernikov tb = (struct ta_buf_ifidx *)ta_buf; 176568394ec8SAlexander V. Chernikov ifname = (char *)tei->paddr; 176668394ec8SAlexander V. Chernikov icfg = (struct iftable_cfg *)ta_state; 176768394ec8SAlexander V. Chernikov ife = tb->ife; 176868394ec8SAlexander V. Chernikov 176968394ec8SAlexander V. Chernikov ife->icfg = icfg; 177068394ec8SAlexander V. Chernikov 177168394ec8SAlexander V. Chernikov tmp = (struct ifentry *)ipfw_objhash_lookup_name(icfg->ii, 0, ifname); 177268394ec8SAlexander V. Chernikov 177368394ec8SAlexander V. Chernikov if (tmp != NULL) { 177468394ec8SAlexander V. Chernikov if ((tei->flags & TEI_FLAGS_UPDATE) == 0) 177568394ec8SAlexander V. Chernikov return (EEXIST); 177668394ec8SAlexander V. Chernikov 1777648e8380SAlexander V. Chernikov /* Exchange values in @tmp and @tei */ 1778648e8380SAlexander V. Chernikov value = tmp->value; 1779648e8380SAlexander V. Chernikov tmp->value = tei->value; 1780648e8380SAlexander V. Chernikov tei->value = value; 178168394ec8SAlexander V. Chernikov 1782648e8380SAlexander V. Chernikov iif = tmp->ic.iface; 178368394ec8SAlexander V. Chernikov if (iif->resolved != 0) { 1784648e8380SAlexander V. Chernikov /* We have to update runtime value, too */ 178568394ec8SAlexander V. Chernikov ifi = ifidx_find(ti, &iif->ifindex); 178668394ec8SAlexander V. Chernikov ifi->value = ife->value; 178768394ec8SAlexander V. Chernikov } 178868394ec8SAlexander V. Chernikov 178968394ec8SAlexander V. Chernikov /* Indicate that update has happened instead of addition */ 179068394ec8SAlexander V. Chernikov tei->flags |= TEI_FLAGS_UPDATED; 1791adea6201SAlexander V. Chernikov *pnum = 0; 179268394ec8SAlexander V. Chernikov return (0); 179368394ec8SAlexander V. Chernikov } 179468394ec8SAlexander V. Chernikov 17954c0c07a5SAlexander V. Chernikov if ((tei->flags & TEI_FLAGS_DONTADD) != 0) 17964c0c07a5SAlexander V. Chernikov return (EFBIG); 17974c0c07a5SAlexander V. Chernikov 179868394ec8SAlexander V. Chernikov /* Link to internal list */ 179968394ec8SAlexander V. Chernikov ipfw_objhash_add(icfg->ii, &ife->no); 180068394ec8SAlexander V. Chernikov 180168394ec8SAlexander V. Chernikov /* Link notifier (possible running its callback) */ 180268394ec8SAlexander V. Chernikov ipfw_iface_add_notify(icfg->ch, &ife->ic); 180368394ec8SAlexander V. Chernikov icfg->count++; 180468394ec8SAlexander V. Chernikov 180568394ec8SAlexander V. Chernikov tb->ife = NULL; 1806adea6201SAlexander V. Chernikov *pnum = 1; 180768394ec8SAlexander V. Chernikov 180868394ec8SAlexander V. Chernikov return (0); 180968394ec8SAlexander V. Chernikov } 181068394ec8SAlexander V. Chernikov 181168394ec8SAlexander V. Chernikov /* 181268394ec8SAlexander V. Chernikov * Prepare to delete key from table. 181368394ec8SAlexander V. Chernikov * Do basic interface name checks. 181468394ec8SAlexander V. Chernikov */ 181568394ec8SAlexander V. Chernikov static int 181668394ec8SAlexander V. Chernikov ta_prepare_del_ifidx(struct ip_fw_chain *ch, struct tentry_info *tei, 181768394ec8SAlexander V. Chernikov void *ta_buf) 18189f7d47b0SAlexander V. Chernikov { 181974b941f0SAlexander V. Chernikov struct ta_buf_ifidx *tb; 1820e0a8b9eeSAlexander V. Chernikov char *ifname; 18219f7d47b0SAlexander V. Chernikov 182274b941f0SAlexander V. Chernikov tb = (struct ta_buf_ifidx *)ta_buf; 18239f7d47b0SAlexander V. Chernikov 18249f7d47b0SAlexander V. Chernikov /* Check if string is terminated */ 1825e0a8b9eeSAlexander V. Chernikov ifname = (char *)tei->paddr; 1826e0a8b9eeSAlexander V. Chernikov if (strnlen(ifname, IF_NAMESIZE) == IF_NAMESIZE) 18279f7d47b0SAlexander V. Chernikov return (EINVAL); 18289f7d47b0SAlexander V. Chernikov 18299f7d47b0SAlexander V. Chernikov return (0); 18309f7d47b0SAlexander V. Chernikov } 18319f7d47b0SAlexander V. Chernikov 183268394ec8SAlexander V. Chernikov /* 183368394ec8SAlexander V. Chernikov * Remove key from both configuration list and 183468394ec8SAlexander V. Chernikov * runtime array. Removed interface notification. 183568394ec8SAlexander V. Chernikov */ 18369f7d47b0SAlexander V. Chernikov static int 1837adea6201SAlexander V. Chernikov ta_del_ifidx(void *ta_state, struct table_info *ti, struct tentry_info *tei, 1838b6ee846eSAlexander V. Chernikov void *ta_buf, uint32_t *pnum) 18399f7d47b0SAlexander V. Chernikov { 184068394ec8SAlexander V. Chernikov struct iftable_cfg *icfg; 184168394ec8SAlexander V. Chernikov struct ifentry *ife; 184268394ec8SAlexander V. Chernikov struct ta_buf_ifidx *tb; 184368394ec8SAlexander V. Chernikov char *ifname; 184468394ec8SAlexander V. Chernikov uint16_t ifindex; 184568394ec8SAlexander V. Chernikov int res; 18469f7d47b0SAlexander V. Chernikov 184768394ec8SAlexander V. Chernikov tb = (struct ta_buf_ifidx *)ta_buf; 184868394ec8SAlexander V. Chernikov ifname = (char *)tei->paddr; 184968394ec8SAlexander V. Chernikov icfg = (struct iftable_cfg *)ta_state; 185068394ec8SAlexander V. Chernikov ife = tb->ife; 18519f7d47b0SAlexander V. Chernikov 185268394ec8SAlexander V. Chernikov ife = (struct ifentry *)ipfw_objhash_lookup_name(icfg->ii, 0, ifname); 18539f7d47b0SAlexander V. Chernikov 185468394ec8SAlexander V. Chernikov if (ife == NULL) 185581d3153dSAlexander V. Chernikov return (ENOENT); 18569f7d47b0SAlexander V. Chernikov 185768394ec8SAlexander V. Chernikov if (ife->linked != 0) { 185868394ec8SAlexander V. Chernikov /* We have to remove item from runtime */ 185968394ec8SAlexander V. Chernikov ifindex = ife->ic.iface->ifindex; 186068394ec8SAlexander V. Chernikov 186168394ec8SAlexander V. Chernikov res = bdel(&ifindex, icfg->main_ptr, icfg->used, 186268394ec8SAlexander V. Chernikov sizeof(struct ifidx), compare_ifidx); 186368394ec8SAlexander V. Chernikov 186468394ec8SAlexander V. Chernikov KASSERT(res == 1, ("index %d does not exist", ifindex)); 186568394ec8SAlexander V. Chernikov icfg->used--; 186668394ec8SAlexander V. Chernikov ti->data = icfg->used; 186768394ec8SAlexander V. Chernikov ife->linked = 0; 186868394ec8SAlexander V. Chernikov } 186968394ec8SAlexander V. Chernikov 187068394ec8SAlexander V. Chernikov /* Unlink from local list */ 187168394ec8SAlexander V. Chernikov ipfw_objhash_del(icfg->ii, &ife->no); 187268394ec8SAlexander V. Chernikov /* Unlink notifier */ 187368394ec8SAlexander V. Chernikov ipfw_iface_del_notify(icfg->ch, &ife->ic); 187468394ec8SAlexander V. Chernikov 187568394ec8SAlexander V. Chernikov icfg->count--; 1876648e8380SAlexander V. Chernikov tei->value = ife->value; 187768394ec8SAlexander V. Chernikov 187868394ec8SAlexander V. Chernikov tb->ife = ife; 1879adea6201SAlexander V. Chernikov *pnum = 1; 188068394ec8SAlexander V. Chernikov 18819f7d47b0SAlexander V. Chernikov return (0); 18829f7d47b0SAlexander V. Chernikov } 18839f7d47b0SAlexander V. Chernikov 188468394ec8SAlexander V. Chernikov /* 188568394ec8SAlexander V. Chernikov * Flush deleted entry. 188668394ec8SAlexander V. Chernikov * Drops interface reference and frees entry. 188768394ec8SAlexander V. Chernikov */ 18889f7d47b0SAlexander V. Chernikov static void 188968394ec8SAlexander V. Chernikov ta_flush_ifidx_entry(struct ip_fw_chain *ch, struct tentry_info *tei, 189068394ec8SAlexander V. Chernikov void *ta_buf) 18919f7d47b0SAlexander V. Chernikov { 189268394ec8SAlexander V. Chernikov struct ta_buf_ifidx *tb; 18939f7d47b0SAlexander V. Chernikov 189468394ec8SAlexander V. Chernikov tb = (struct ta_buf_ifidx *)ta_buf; 18959f7d47b0SAlexander V. Chernikov 189668394ec8SAlexander V. Chernikov if (tb->ife != NULL) { 189768394ec8SAlexander V. Chernikov /* Unlink first */ 189868394ec8SAlexander V. Chernikov ipfw_iface_unref(ch, &tb->ife->ic); 189968394ec8SAlexander V. Chernikov free(tb->ife, M_IPFW_TBL); 190068394ec8SAlexander V. Chernikov } 190168394ec8SAlexander V. Chernikov } 190268394ec8SAlexander V. Chernikov 190368394ec8SAlexander V. Chernikov 190468394ec8SAlexander V. Chernikov /* 190568394ec8SAlexander V. Chernikov * Handle interface announce/withdrawal for particular table. 190668394ec8SAlexander V. Chernikov * Every real runtime array modification happens here. 190768394ec8SAlexander V. Chernikov */ 190868394ec8SAlexander V. Chernikov static void 190968394ec8SAlexander V. Chernikov if_notifier(struct ip_fw_chain *ch, void *cbdata, uint16_t ifindex) 191068394ec8SAlexander V. Chernikov { 191168394ec8SAlexander V. Chernikov struct ifentry *ife; 191268394ec8SAlexander V. Chernikov struct ifidx ifi; 191368394ec8SAlexander V. Chernikov struct iftable_cfg *icfg; 191468394ec8SAlexander V. Chernikov struct table_info *ti; 191568394ec8SAlexander V. Chernikov int res; 191668394ec8SAlexander V. Chernikov 191768394ec8SAlexander V. Chernikov ife = (struct ifentry *)cbdata; 191868394ec8SAlexander V. Chernikov icfg = ife->icfg; 191968394ec8SAlexander V. Chernikov ti = icfg->ti; 192068394ec8SAlexander V. Chernikov 192168394ec8SAlexander V. Chernikov KASSERT(ti != NULL, ("ti=NULL, check change_ti handler")); 192268394ec8SAlexander V. Chernikov 192368394ec8SAlexander V. Chernikov if (ife->linked == 0 && ifindex != 0) { 192468394ec8SAlexander V. Chernikov /* Interface announce */ 192568394ec8SAlexander V. Chernikov ifi.kidx = ifindex; 192668394ec8SAlexander V. Chernikov ifi.spare = 0; 192768394ec8SAlexander V. Chernikov ifi.value = ife->value; 192868394ec8SAlexander V. Chernikov res = badd(&ifindex, &ifi, icfg->main_ptr, icfg->used, 192968394ec8SAlexander V. Chernikov sizeof(struct ifidx), compare_ifidx); 193068394ec8SAlexander V. Chernikov KASSERT(res == 1, ("index %d already exists", ifindex)); 193168394ec8SAlexander V. Chernikov icfg->used++; 193268394ec8SAlexander V. Chernikov ti->data = icfg->used; 193368394ec8SAlexander V. Chernikov ife->linked = 1; 193468394ec8SAlexander V. Chernikov } else if (ife->linked != 0 && ifindex == 0) { 193568394ec8SAlexander V. Chernikov /* Interface withdrawal */ 193668394ec8SAlexander V. Chernikov ifindex = ife->ic.iface->ifindex; 193768394ec8SAlexander V. Chernikov 193868394ec8SAlexander V. Chernikov res = bdel(&ifindex, icfg->main_ptr, icfg->used, 193968394ec8SAlexander V. Chernikov sizeof(struct ifidx), compare_ifidx); 194068394ec8SAlexander V. Chernikov 194168394ec8SAlexander V. Chernikov KASSERT(res == 1, ("index %d does not exist", ifindex)); 194268394ec8SAlexander V. Chernikov icfg->used--; 194368394ec8SAlexander V. Chernikov ti->data = icfg->used; 194468394ec8SAlexander V. Chernikov ife->linked = 0; 194568394ec8SAlexander V. Chernikov } 194668394ec8SAlexander V. Chernikov } 194768394ec8SAlexander V. Chernikov 194868394ec8SAlexander V. Chernikov 194968394ec8SAlexander V. Chernikov /* 195068394ec8SAlexander V. Chernikov * Table growing callbacks. 195168394ec8SAlexander V. Chernikov */ 195268394ec8SAlexander V. Chernikov 1953b6ee846eSAlexander V. Chernikov static int 1954b6ee846eSAlexander V. Chernikov ta_has_space_ifidx(void *ta_state, struct table_info *ti, uint32_t count, 1955b6ee846eSAlexander V. Chernikov uint64_t *pflags) 1956b6ee846eSAlexander V. Chernikov { 1957b6ee846eSAlexander V. Chernikov struct iftable_cfg *cfg; 19580bce0c23SAlexander V. Chernikov uint32_t size; 1959b6ee846eSAlexander V. Chernikov 1960b6ee846eSAlexander V. Chernikov cfg = (struct iftable_cfg *)ta_state; 1961b6ee846eSAlexander V. Chernikov 19620bce0c23SAlexander V. Chernikov size = cfg->size; 19630bce0c23SAlexander V. Chernikov while (size < cfg->count + count) 19640bce0c23SAlexander V. Chernikov size *= 2; 19650bce0c23SAlexander V. Chernikov 19660bce0c23SAlexander V. Chernikov if (size != cfg->size) { 19670bce0c23SAlexander V. Chernikov *pflags = size; 1968b6ee846eSAlexander V. Chernikov return (0); 1969b6ee846eSAlexander V. Chernikov } 1970b6ee846eSAlexander V. Chernikov 1971b6ee846eSAlexander V. Chernikov return (1); 1972b6ee846eSAlexander V. Chernikov } 1973b6ee846eSAlexander V. Chernikov 197468394ec8SAlexander V. Chernikov /* 197568394ec8SAlexander V. Chernikov * Allocate ned, larger runtime ifidx array. 197668394ec8SAlexander V. Chernikov */ 197768394ec8SAlexander V. Chernikov static int 197868394ec8SAlexander V. Chernikov ta_prepare_mod_ifidx(void *ta_buf, uint64_t *pflags) 197968394ec8SAlexander V. Chernikov { 19800bce0c23SAlexander V. Chernikov struct mod_item *mi; 198168394ec8SAlexander V. Chernikov 19820bce0c23SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 198368394ec8SAlexander V. Chernikov 19840bce0c23SAlexander V. Chernikov memset(mi, 0, sizeof(struct mod_item)); 198568394ec8SAlexander V. Chernikov mi->size = *pflags; 198668394ec8SAlexander V. Chernikov mi->main_ptr = malloc(sizeof(struct ifidx) * mi->size, M_IPFW, 198768394ec8SAlexander V. Chernikov M_WAITOK | M_ZERO); 198868394ec8SAlexander V. Chernikov 198968394ec8SAlexander V. Chernikov return (0); 199068394ec8SAlexander V. Chernikov } 199168394ec8SAlexander V. Chernikov 199268394ec8SAlexander V. Chernikov /* 199368394ec8SAlexander V. Chernikov * Copy data from old runtime array to new one. 199468394ec8SAlexander V. Chernikov */ 199568394ec8SAlexander V. Chernikov static int 199668394ec8SAlexander V. Chernikov ta_fill_mod_ifidx(void *ta_state, struct table_info *ti, void *ta_buf, 199768394ec8SAlexander V. Chernikov uint64_t *pflags) 199868394ec8SAlexander V. Chernikov { 19990bce0c23SAlexander V. Chernikov struct mod_item *mi; 200068394ec8SAlexander V. Chernikov struct iftable_cfg *icfg; 200168394ec8SAlexander V. Chernikov 20020bce0c23SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 200368394ec8SAlexander V. Chernikov icfg = (struct iftable_cfg *)ta_state; 200468394ec8SAlexander V. Chernikov 200568394ec8SAlexander V. Chernikov /* Check if we still need to grow array */ 200668394ec8SAlexander V. Chernikov if (icfg->size >= mi->size) { 200768394ec8SAlexander V. Chernikov *pflags = 0; 200868394ec8SAlexander V. Chernikov return (0); 200968394ec8SAlexander V. Chernikov } 201068394ec8SAlexander V. Chernikov 201168394ec8SAlexander V. Chernikov memcpy(mi->main_ptr, icfg->main_ptr, icfg->used * sizeof(struct ifidx)); 201268394ec8SAlexander V. Chernikov 201368394ec8SAlexander V. Chernikov return (0); 201468394ec8SAlexander V. Chernikov } 201568394ec8SAlexander V. Chernikov 201668394ec8SAlexander V. Chernikov /* 201768394ec8SAlexander V. Chernikov * Switch old & new arrays. 201868394ec8SAlexander V. Chernikov */ 201968394ec8SAlexander V. Chernikov static int 202068394ec8SAlexander V. Chernikov ta_modify_ifidx(void *ta_state, struct table_info *ti, void *ta_buf, 202168394ec8SAlexander V. Chernikov uint64_t pflags) 202268394ec8SAlexander V. Chernikov { 20230bce0c23SAlexander V. Chernikov struct mod_item *mi; 202468394ec8SAlexander V. Chernikov struct iftable_cfg *icfg; 202568394ec8SAlexander V. Chernikov void *old_ptr; 202668394ec8SAlexander V. Chernikov 20270bce0c23SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 202868394ec8SAlexander V. Chernikov icfg = (struct iftable_cfg *)ta_state; 202968394ec8SAlexander V. Chernikov 203068394ec8SAlexander V. Chernikov old_ptr = icfg->main_ptr; 203168394ec8SAlexander V. Chernikov icfg->main_ptr = mi->main_ptr; 203268394ec8SAlexander V. Chernikov icfg->size = mi->size; 203368394ec8SAlexander V. Chernikov ti->state = icfg->main_ptr; 203468394ec8SAlexander V. Chernikov 203568394ec8SAlexander V. Chernikov mi->main_ptr = old_ptr; 203668394ec8SAlexander V. Chernikov 203768394ec8SAlexander V. Chernikov return (0); 203868394ec8SAlexander V. Chernikov } 203968394ec8SAlexander V. Chernikov 204068394ec8SAlexander V. Chernikov /* 204168394ec8SAlexander V. Chernikov * Free unneded array. 204268394ec8SAlexander V. Chernikov */ 204368394ec8SAlexander V. Chernikov static void 204468394ec8SAlexander V. Chernikov ta_flush_mod_ifidx(void *ta_buf) 204568394ec8SAlexander V. Chernikov { 20460bce0c23SAlexander V. Chernikov struct mod_item *mi; 204768394ec8SAlexander V. Chernikov 20480bce0c23SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 204968394ec8SAlexander V. Chernikov if (mi->main_ptr != NULL) 205068394ec8SAlexander V. Chernikov free(mi->main_ptr, M_IPFW); 20519f7d47b0SAlexander V. Chernikov } 20529f7d47b0SAlexander V. Chernikov 20539f7d47b0SAlexander V. Chernikov static int 205468394ec8SAlexander V. Chernikov ta_dump_ifidx_tentry(void *ta_state, struct table_info *ti, void *e, 205581d3153dSAlexander V. Chernikov ipfw_obj_tentry *tent) 20569f7d47b0SAlexander V. Chernikov { 205768394ec8SAlexander V. Chernikov struct ifentry *ife; 20589f7d47b0SAlexander V. Chernikov 205968394ec8SAlexander V. Chernikov ife = (struct ifentry *)e; 206068394ec8SAlexander V. Chernikov 206181d3153dSAlexander V. Chernikov tent->masklen = 8 * IF_NAMESIZE; 206268394ec8SAlexander V. Chernikov memcpy(&tent->k, ife->no.name, IF_NAMESIZE); 206368394ec8SAlexander V. Chernikov tent->value = ife->value; 20649f7d47b0SAlexander V. Chernikov 20659f7d47b0SAlexander V. Chernikov return (0); 20669f7d47b0SAlexander V. Chernikov } 20679f7d47b0SAlexander V. Chernikov 206881d3153dSAlexander V. Chernikov static int 2069914bffb6SAlexander V. Chernikov ta_find_ifidx_tentry(void *ta_state, struct table_info *ti, 2070914bffb6SAlexander V. Chernikov ipfw_obj_tentry *tent) 207181d3153dSAlexander V. Chernikov { 207268394ec8SAlexander V. Chernikov struct iftable_cfg *icfg; 207368394ec8SAlexander V. Chernikov struct ifentry *ife; 207468394ec8SAlexander V. Chernikov char *ifname; 207581d3153dSAlexander V. Chernikov 207668394ec8SAlexander V. Chernikov icfg = (struct iftable_cfg *)ta_state; 2077914bffb6SAlexander V. Chernikov ifname = tent->k.iface; 207881d3153dSAlexander V. Chernikov 207968394ec8SAlexander V. Chernikov if (strnlen(ifname, IF_NAMESIZE) == IF_NAMESIZE) 208068394ec8SAlexander V. Chernikov return (EINVAL); 208181d3153dSAlexander V. Chernikov 208268394ec8SAlexander V. Chernikov ife = (struct ifentry *)ipfw_objhash_lookup_name(icfg->ii, 0, ifname); 208368394ec8SAlexander V. Chernikov 208468394ec8SAlexander V. Chernikov if (ife != NULL) { 208568394ec8SAlexander V. Chernikov ta_dump_ifidx_tentry(ta_state, ti, ife, tent); 208681d3153dSAlexander V. Chernikov return (0); 208781d3153dSAlexander V. Chernikov } 208881d3153dSAlexander V. Chernikov 208981d3153dSAlexander V. Chernikov return (ENOENT); 209081d3153dSAlexander V. Chernikov } 209181d3153dSAlexander V. Chernikov 209268394ec8SAlexander V. Chernikov struct wa_ifidx { 209368394ec8SAlexander V. Chernikov ta_foreach_f *f; 209468394ec8SAlexander V. Chernikov void *arg; 209568394ec8SAlexander V. Chernikov }; 209668394ec8SAlexander V. Chernikov 20979f7d47b0SAlexander V. Chernikov static void 209868394ec8SAlexander V. Chernikov foreach_ifidx(struct namedobj_instance *ii, struct named_object *no, 20999f7d47b0SAlexander V. Chernikov void *arg) 21009f7d47b0SAlexander V. Chernikov { 210168394ec8SAlexander V. Chernikov struct ifentry *ife; 210268394ec8SAlexander V. Chernikov struct wa_ifidx *wa; 21039f7d47b0SAlexander V. Chernikov 210468394ec8SAlexander V. Chernikov ife = (struct ifentry *)no; 210568394ec8SAlexander V. Chernikov wa = (struct wa_ifidx *)arg; 210668394ec8SAlexander V. Chernikov 210768394ec8SAlexander V. Chernikov wa->f(ife, wa->arg); 21089f7d47b0SAlexander V. Chernikov } 21099f7d47b0SAlexander V. Chernikov 211068394ec8SAlexander V. Chernikov static void 211168394ec8SAlexander V. Chernikov ta_foreach_ifidx(void *ta_state, struct table_info *ti, ta_foreach_f *f, 211268394ec8SAlexander V. Chernikov void *arg) 211368394ec8SAlexander V. Chernikov { 211468394ec8SAlexander V. Chernikov struct iftable_cfg *icfg; 211568394ec8SAlexander V. Chernikov struct wa_ifidx wa; 211668394ec8SAlexander V. Chernikov 211768394ec8SAlexander V. Chernikov icfg = (struct iftable_cfg *)ta_state; 211868394ec8SAlexander V. Chernikov 211968394ec8SAlexander V. Chernikov wa.f = f; 212068394ec8SAlexander V. Chernikov wa.arg = arg; 212168394ec8SAlexander V. Chernikov 212268394ec8SAlexander V. Chernikov ipfw_objhash_foreach(icfg->ii, foreach_ifidx, &wa); 212368394ec8SAlexander V. Chernikov } 212468394ec8SAlexander V. Chernikov 212574b941f0SAlexander V. Chernikov struct table_algo iface_idx = { 2126adea6201SAlexander V. Chernikov .name = "iface:array", 21279d099b4fSAlexander V. Chernikov .type = IPFW_TABLE_INTERFACE, 212857a1cf95SAlexander V. Chernikov .flags = TA_FLAG_DEFAULT, 212957a1cf95SAlexander V. Chernikov .ta_buf_size = sizeof(struct ta_buf_ifidx), 213068394ec8SAlexander V. Chernikov .init = ta_init_ifidx, 213168394ec8SAlexander V. Chernikov .destroy = ta_destroy_ifidx, 213268394ec8SAlexander V. Chernikov .prepare_add = ta_prepare_add_ifidx, 213368394ec8SAlexander V. Chernikov .prepare_del = ta_prepare_del_ifidx, 213468394ec8SAlexander V. Chernikov .add = ta_add_ifidx, 213568394ec8SAlexander V. Chernikov .del = ta_del_ifidx, 213668394ec8SAlexander V. Chernikov .flush_entry = ta_flush_ifidx_entry, 213768394ec8SAlexander V. Chernikov .foreach = ta_foreach_ifidx, 213868394ec8SAlexander V. Chernikov .dump_tentry = ta_dump_ifidx_tentry, 213968394ec8SAlexander V. Chernikov .find_tentry = ta_find_ifidx_tentry, 2140b6ee846eSAlexander V. Chernikov .has_space = ta_has_space_ifidx, 214168394ec8SAlexander V. Chernikov .prepare_mod = ta_prepare_mod_ifidx, 214268394ec8SAlexander V. Chernikov .fill_mod = ta_fill_mod_ifidx, 214368394ec8SAlexander V. Chernikov .modify = ta_modify_ifidx, 214468394ec8SAlexander V. Chernikov .flush_mod = ta_flush_mod_ifidx, 214568394ec8SAlexander V. Chernikov .change_ti = ta_change_ti_ifidx, 21469f7d47b0SAlexander V. Chernikov }; 21479f7d47b0SAlexander V. Chernikov 2148b23d5de9SAlexander V. Chernikov /* 2149b23d5de9SAlexander V. Chernikov * Number array cmds. 2150b23d5de9SAlexander V. Chernikov * 2151b23d5de9SAlexander V. Chernikov * Implementation: 2152b23d5de9SAlexander V. Chernikov * 2153b23d5de9SAlexander V. Chernikov * Runtime part: 2154b23d5de9SAlexander V. Chernikov * - sorted array of "struct numarray" pointed by ti->state. 2155b23d5de9SAlexander V. Chernikov * Array is allocated with rounding up to NUMARRAY_CHUNK. 2156b23d5de9SAlexander V. Chernikov * - current array size is stored in ti->data 2157b23d5de9SAlexander V. Chernikov * 2158b23d5de9SAlexander V. Chernikov */ 2159b23d5de9SAlexander V. Chernikov 2160b23d5de9SAlexander V. Chernikov struct numarray { 2161b23d5de9SAlexander V. Chernikov uint32_t number; 2162b23d5de9SAlexander V. Chernikov uint32_t value; 2163b23d5de9SAlexander V. Chernikov }; 2164b23d5de9SAlexander V. Chernikov 2165b23d5de9SAlexander V. Chernikov struct numarray_cfg { 2166b23d5de9SAlexander V. Chernikov void *main_ptr; 2167b23d5de9SAlexander V. Chernikov size_t size; /* Number of items allocated in array */ 2168b23d5de9SAlexander V. Chernikov size_t used; /* Number of items _active_ now */ 2169b23d5de9SAlexander V. Chernikov }; 2170b23d5de9SAlexander V. Chernikov 21710bce0c23SAlexander V. Chernikov struct ta_buf_numarray 21720bce0c23SAlexander V. Chernikov { 21730bce0c23SAlexander V. Chernikov struct numarray na; 21740bce0c23SAlexander V. Chernikov }; 2175b23d5de9SAlexander V. Chernikov 2176b23d5de9SAlexander V. Chernikov int compare_numarray(const void *k, const void *v); 2177b23d5de9SAlexander V. Chernikov 2178b23d5de9SAlexander V. Chernikov int 2179b23d5de9SAlexander V. Chernikov compare_numarray(const void *k, const void *v) 2180b23d5de9SAlexander V. Chernikov { 2181b23d5de9SAlexander V. Chernikov struct numarray *na; 2182b23d5de9SAlexander V. Chernikov uint32_t key; 2183b23d5de9SAlexander V. Chernikov 2184b23d5de9SAlexander V. Chernikov key = *((uint32_t *)k); 2185b23d5de9SAlexander V. Chernikov na = (struct numarray *)v; 2186b23d5de9SAlexander V. Chernikov 2187b23d5de9SAlexander V. Chernikov if (key < na->number) 2188b23d5de9SAlexander V. Chernikov return (-1); 2189b23d5de9SAlexander V. Chernikov else if (key > na->number) 2190b23d5de9SAlexander V. Chernikov return (1); 2191b23d5de9SAlexander V. Chernikov 2192b23d5de9SAlexander V. Chernikov return (0); 2193b23d5de9SAlexander V. Chernikov } 2194b23d5de9SAlexander V. Chernikov 2195b23d5de9SAlexander V. Chernikov static struct numarray * 2196b23d5de9SAlexander V. Chernikov numarray_find(struct table_info *ti, void *key) 2197b23d5de9SAlexander V. Chernikov { 2198b23d5de9SAlexander V. Chernikov struct numarray *ri; 2199b23d5de9SAlexander V. Chernikov 2200b23d5de9SAlexander V. Chernikov ri = bsearch(key, ti->state, ti->data, sizeof(struct numarray), 2201b23d5de9SAlexander V. Chernikov compare_ifidx); 2202b23d5de9SAlexander V. Chernikov 2203b23d5de9SAlexander V. Chernikov return (ri); 2204b23d5de9SAlexander V. Chernikov } 2205b23d5de9SAlexander V. Chernikov 2206b23d5de9SAlexander V. Chernikov static int 2207b23d5de9SAlexander V. Chernikov ta_lookup_numarray(struct table_info *ti, void *key, uint32_t keylen, 2208b23d5de9SAlexander V. Chernikov uint32_t *val) 2209b23d5de9SAlexander V. Chernikov { 2210b23d5de9SAlexander V. Chernikov struct numarray *ri; 2211b23d5de9SAlexander V. Chernikov 2212b23d5de9SAlexander V. Chernikov ri = numarray_find(ti, key); 2213b23d5de9SAlexander V. Chernikov 2214b23d5de9SAlexander V. Chernikov if (ri != NULL) { 2215b23d5de9SAlexander V. Chernikov *val = ri->value; 2216b23d5de9SAlexander V. Chernikov return (1); 2217b23d5de9SAlexander V. Chernikov } 2218b23d5de9SAlexander V. Chernikov 2219b23d5de9SAlexander V. Chernikov return (0); 2220b23d5de9SAlexander V. Chernikov } 2221b23d5de9SAlexander V. Chernikov 2222b23d5de9SAlexander V. Chernikov static int 2223b23d5de9SAlexander V. Chernikov ta_init_numarray(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti, 2224914bffb6SAlexander V. Chernikov char *data, uint8_t tflags) 2225b23d5de9SAlexander V. Chernikov { 2226b23d5de9SAlexander V. Chernikov struct numarray_cfg *cfg; 2227b23d5de9SAlexander V. Chernikov 2228b23d5de9SAlexander V. Chernikov cfg = malloc(sizeof(*cfg), M_IPFW, M_WAITOK | M_ZERO); 2229b23d5de9SAlexander V. Chernikov 22300bce0c23SAlexander V. Chernikov cfg->size = 16; 2231b23d5de9SAlexander V. Chernikov cfg->main_ptr = malloc(sizeof(struct numarray) * cfg->size, M_IPFW, 2232b23d5de9SAlexander V. Chernikov M_WAITOK | M_ZERO); 2233b23d5de9SAlexander V. Chernikov 2234b23d5de9SAlexander V. Chernikov *ta_state = cfg; 2235b23d5de9SAlexander V. Chernikov ti->state = cfg->main_ptr; 2236b23d5de9SAlexander V. Chernikov ti->lookup = ta_lookup_numarray; 2237b23d5de9SAlexander V. Chernikov 2238b23d5de9SAlexander V. Chernikov return (0); 2239b23d5de9SAlexander V. Chernikov } 2240b23d5de9SAlexander V. Chernikov 2241b23d5de9SAlexander V. Chernikov /* 2242b23d5de9SAlexander V. Chernikov * Destroys table @ti 2243b23d5de9SAlexander V. Chernikov */ 2244b23d5de9SAlexander V. Chernikov static void 2245b23d5de9SAlexander V. Chernikov ta_destroy_numarray(void *ta_state, struct table_info *ti) 2246b23d5de9SAlexander V. Chernikov { 2247b23d5de9SAlexander V. Chernikov struct numarray_cfg *cfg; 2248b23d5de9SAlexander V. Chernikov 2249b23d5de9SAlexander V. Chernikov cfg = (struct numarray_cfg *)ta_state; 2250b23d5de9SAlexander V. Chernikov 2251b23d5de9SAlexander V. Chernikov if (cfg->main_ptr != NULL) 2252b23d5de9SAlexander V. Chernikov free(cfg->main_ptr, M_IPFW); 2253b23d5de9SAlexander V. Chernikov 2254b23d5de9SAlexander V. Chernikov free(cfg, M_IPFW); 2255b23d5de9SAlexander V. Chernikov } 2256b23d5de9SAlexander V. Chernikov 2257b23d5de9SAlexander V. Chernikov /* 2258b23d5de9SAlexander V. Chernikov * Prepare for addition/deletion to an array. 2259b23d5de9SAlexander V. Chernikov */ 2260b23d5de9SAlexander V. Chernikov static int 2261b23d5de9SAlexander V. Chernikov ta_prepare_add_numarray(struct ip_fw_chain *ch, struct tentry_info *tei, 2262b23d5de9SAlexander V. Chernikov void *ta_buf) 2263b23d5de9SAlexander V. Chernikov { 2264b23d5de9SAlexander V. Chernikov struct ta_buf_numarray *tb; 2265b23d5de9SAlexander V. Chernikov 2266b23d5de9SAlexander V. Chernikov tb = (struct ta_buf_numarray *)ta_buf; 2267b23d5de9SAlexander V. Chernikov 2268b23d5de9SAlexander V. Chernikov tb->na.number = *((uint32_t *)tei->paddr); 2269b23d5de9SAlexander V. Chernikov tb->na.value = tei->value; 2270b23d5de9SAlexander V. Chernikov 2271b23d5de9SAlexander V. Chernikov return (0); 2272b23d5de9SAlexander V. Chernikov } 2273b23d5de9SAlexander V. Chernikov 2274b23d5de9SAlexander V. Chernikov static int 2275b23d5de9SAlexander V. Chernikov ta_add_numarray(void *ta_state, struct table_info *ti, struct tentry_info *tei, 2276b6ee846eSAlexander V. Chernikov void *ta_buf, uint32_t *pnum) 2277b23d5de9SAlexander V. Chernikov { 2278b23d5de9SAlexander V. Chernikov struct numarray_cfg *cfg; 2279b23d5de9SAlexander V. Chernikov struct ta_buf_numarray *tb; 2280b23d5de9SAlexander V. Chernikov struct numarray *ri; 2281b23d5de9SAlexander V. Chernikov int res; 2282648e8380SAlexander V. Chernikov uint32_t value; 2283b23d5de9SAlexander V. Chernikov 2284b23d5de9SAlexander V. Chernikov tb = (struct ta_buf_numarray *)ta_buf; 2285b23d5de9SAlexander V. Chernikov cfg = (struct numarray_cfg *)ta_state; 2286b23d5de9SAlexander V. Chernikov 2287b23d5de9SAlexander V. Chernikov ri = numarray_find(ti, &tb->na.number); 2288b23d5de9SAlexander V. Chernikov 2289b23d5de9SAlexander V. Chernikov if (ri != NULL) { 2290b23d5de9SAlexander V. Chernikov if ((tei->flags & TEI_FLAGS_UPDATE) == 0) 2291b23d5de9SAlexander V. Chernikov return (EEXIST); 2292b23d5de9SAlexander V. Chernikov 2293648e8380SAlexander V. Chernikov /* Exchange values between ri and @tei */ 2294648e8380SAlexander V. Chernikov value = ri->value; 2295648e8380SAlexander V. Chernikov ri->value = tei->value; 2296648e8380SAlexander V. Chernikov tei->value = value; 2297b23d5de9SAlexander V. Chernikov /* Indicate that update has happened instead of addition */ 2298b23d5de9SAlexander V. Chernikov tei->flags |= TEI_FLAGS_UPDATED; 2299b23d5de9SAlexander V. Chernikov *pnum = 0; 2300b23d5de9SAlexander V. Chernikov return (0); 2301b23d5de9SAlexander V. Chernikov } 2302b23d5de9SAlexander V. Chernikov 23034c0c07a5SAlexander V. Chernikov if ((tei->flags & TEI_FLAGS_DONTADD) != 0) 23044c0c07a5SAlexander V. Chernikov return (EFBIG); 23054c0c07a5SAlexander V. Chernikov 2306b23d5de9SAlexander V. Chernikov res = badd(&tb->na.number, &tb->na, cfg->main_ptr, cfg->used, 2307b23d5de9SAlexander V. Chernikov sizeof(struct numarray), compare_numarray); 2308b23d5de9SAlexander V. Chernikov 2309b23d5de9SAlexander V. Chernikov KASSERT(res == 1, ("number %d already exists", tb->na.number)); 2310b23d5de9SAlexander V. Chernikov cfg->used++; 2311b23d5de9SAlexander V. Chernikov ti->data = cfg->used; 2312b23d5de9SAlexander V. Chernikov *pnum = 1; 2313b23d5de9SAlexander V. Chernikov 2314b23d5de9SAlexander V. Chernikov return (0); 2315b23d5de9SAlexander V. Chernikov } 2316b23d5de9SAlexander V. Chernikov 2317b23d5de9SAlexander V. Chernikov /* 2318b23d5de9SAlexander V. Chernikov * Remove key from both configuration list and 2319b23d5de9SAlexander V. Chernikov * runtime array. Removed interface notification. 2320b23d5de9SAlexander V. Chernikov */ 2321b23d5de9SAlexander V. Chernikov static int 2322b23d5de9SAlexander V. Chernikov ta_del_numarray(void *ta_state, struct table_info *ti, struct tentry_info *tei, 2323b6ee846eSAlexander V. Chernikov void *ta_buf, uint32_t *pnum) 2324b23d5de9SAlexander V. Chernikov { 2325b23d5de9SAlexander V. Chernikov struct numarray_cfg *cfg; 2326b23d5de9SAlexander V. Chernikov struct ta_buf_numarray *tb; 2327b23d5de9SAlexander V. Chernikov struct numarray *ri; 2328b23d5de9SAlexander V. Chernikov int res; 2329b23d5de9SAlexander V. Chernikov 2330b23d5de9SAlexander V. Chernikov tb = (struct ta_buf_numarray *)ta_buf; 2331b23d5de9SAlexander V. Chernikov cfg = (struct numarray_cfg *)ta_state; 2332b23d5de9SAlexander V. Chernikov 2333b23d5de9SAlexander V. Chernikov ri = numarray_find(ti, &tb->na.number); 2334b23d5de9SAlexander V. Chernikov if (ri == NULL) 2335b23d5de9SAlexander V. Chernikov return (ENOENT); 2336b23d5de9SAlexander V. Chernikov 2337648e8380SAlexander V. Chernikov tei->value = ri->value; 2338648e8380SAlexander V. Chernikov 2339b23d5de9SAlexander V. Chernikov res = bdel(&tb->na.number, cfg->main_ptr, cfg->used, 2340b23d5de9SAlexander V. Chernikov sizeof(struct numarray), compare_numarray); 2341b23d5de9SAlexander V. Chernikov 2342b23d5de9SAlexander V. Chernikov KASSERT(res == 1, ("number %u does not exist", tb->na.number)); 2343b23d5de9SAlexander V. Chernikov cfg->used--; 2344b23d5de9SAlexander V. Chernikov ti->data = cfg->used; 2345b23d5de9SAlexander V. Chernikov *pnum = 1; 2346b23d5de9SAlexander V. Chernikov 2347b23d5de9SAlexander V. Chernikov return (0); 2348b23d5de9SAlexander V. Chernikov } 2349b23d5de9SAlexander V. Chernikov 2350b23d5de9SAlexander V. Chernikov static void 2351b23d5de9SAlexander V. Chernikov ta_flush_numarray_entry(struct ip_fw_chain *ch, struct tentry_info *tei, 2352b23d5de9SAlexander V. Chernikov void *ta_buf) 2353b23d5de9SAlexander V. Chernikov { 2354b23d5de9SAlexander V. Chernikov 23550bce0c23SAlexander V. Chernikov /* We don't have any state, do nothing */ 2356b23d5de9SAlexander V. Chernikov } 2357b23d5de9SAlexander V. Chernikov 2358b23d5de9SAlexander V. Chernikov 2359b23d5de9SAlexander V. Chernikov /* 2360b23d5de9SAlexander V. Chernikov * Table growing callbacks. 2361b23d5de9SAlexander V. Chernikov */ 2362b23d5de9SAlexander V. Chernikov 2363b6ee846eSAlexander V. Chernikov static int 2364b6ee846eSAlexander V. Chernikov ta_has_space_numarray(void *ta_state, struct table_info *ti, uint32_t count, 2365b6ee846eSAlexander V. Chernikov uint64_t *pflags) 2366b6ee846eSAlexander V. Chernikov { 2367b6ee846eSAlexander V. Chernikov struct numarray_cfg *cfg; 23680bce0c23SAlexander V. Chernikov size_t size; 2369b6ee846eSAlexander V. Chernikov 2370b6ee846eSAlexander V. Chernikov cfg = (struct numarray_cfg *)ta_state; 2371b6ee846eSAlexander V. Chernikov 23720bce0c23SAlexander V. Chernikov size = cfg->size; 23730bce0c23SAlexander V. Chernikov while (size < cfg->used + count) 23740bce0c23SAlexander V. Chernikov size *= 2; 23750bce0c23SAlexander V. Chernikov 23760bce0c23SAlexander V. Chernikov if (size != cfg->size) { 23770bce0c23SAlexander V. Chernikov *pflags = size; 2378b6ee846eSAlexander V. Chernikov return (0); 2379b6ee846eSAlexander V. Chernikov } 2380b6ee846eSAlexander V. Chernikov 2381b6ee846eSAlexander V. Chernikov return (1); 2382b6ee846eSAlexander V. Chernikov } 2383b6ee846eSAlexander V. Chernikov 2384b23d5de9SAlexander V. Chernikov /* 2385b6ee846eSAlexander V. Chernikov * Allocate new, larger runtime array. 2386b23d5de9SAlexander V. Chernikov */ 2387b23d5de9SAlexander V. Chernikov static int 2388b23d5de9SAlexander V. Chernikov ta_prepare_mod_numarray(void *ta_buf, uint64_t *pflags) 2389b23d5de9SAlexander V. Chernikov { 2390b23d5de9SAlexander V. Chernikov struct mod_item *mi; 2391b23d5de9SAlexander V. Chernikov 2392b23d5de9SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 2393b23d5de9SAlexander V. Chernikov 2394b23d5de9SAlexander V. Chernikov memset(mi, 0, sizeof(struct mod_item)); 2395b23d5de9SAlexander V. Chernikov mi->size = *pflags; 2396b23d5de9SAlexander V. Chernikov mi->main_ptr = malloc(sizeof(struct numarray) * mi->size, M_IPFW, 2397b23d5de9SAlexander V. Chernikov M_WAITOK | M_ZERO); 2398b23d5de9SAlexander V. Chernikov 2399b23d5de9SAlexander V. Chernikov return (0); 2400b23d5de9SAlexander V. Chernikov } 2401b23d5de9SAlexander V. Chernikov 2402b23d5de9SAlexander V. Chernikov /* 2403b23d5de9SAlexander V. Chernikov * Copy data from old runtime array to new one. 2404b23d5de9SAlexander V. Chernikov */ 2405b23d5de9SAlexander V. Chernikov static int 2406b23d5de9SAlexander V. Chernikov ta_fill_mod_numarray(void *ta_state, struct table_info *ti, void *ta_buf, 2407b23d5de9SAlexander V. Chernikov uint64_t *pflags) 2408b23d5de9SAlexander V. Chernikov { 2409b23d5de9SAlexander V. Chernikov struct mod_item *mi; 2410b23d5de9SAlexander V. Chernikov struct numarray_cfg *cfg; 2411b23d5de9SAlexander V. Chernikov 2412b23d5de9SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 2413b23d5de9SAlexander V. Chernikov cfg = (struct numarray_cfg *)ta_state; 2414b23d5de9SAlexander V. Chernikov 2415b23d5de9SAlexander V. Chernikov /* Check if we still need to grow array */ 2416b23d5de9SAlexander V. Chernikov if (cfg->size >= mi->size) { 2417b23d5de9SAlexander V. Chernikov *pflags = 0; 2418b23d5de9SAlexander V. Chernikov return (0); 2419b23d5de9SAlexander V. Chernikov } 2420b23d5de9SAlexander V. Chernikov 2421b23d5de9SAlexander V. Chernikov memcpy(mi->main_ptr, cfg->main_ptr, cfg->used * sizeof(struct numarray)); 2422b23d5de9SAlexander V. Chernikov 2423b23d5de9SAlexander V. Chernikov return (0); 2424b23d5de9SAlexander V. Chernikov } 2425b23d5de9SAlexander V. Chernikov 2426b23d5de9SAlexander V. Chernikov /* 2427b23d5de9SAlexander V. Chernikov * Switch old & new arrays. 2428b23d5de9SAlexander V. Chernikov */ 2429b23d5de9SAlexander V. Chernikov static int 2430b23d5de9SAlexander V. Chernikov ta_modify_numarray(void *ta_state, struct table_info *ti, void *ta_buf, 2431b23d5de9SAlexander V. Chernikov uint64_t pflags) 2432b23d5de9SAlexander V. Chernikov { 2433b23d5de9SAlexander V. Chernikov struct mod_item *mi; 2434b23d5de9SAlexander V. Chernikov struct numarray_cfg *cfg; 2435b23d5de9SAlexander V. Chernikov void *old_ptr; 2436b23d5de9SAlexander V. Chernikov 2437b23d5de9SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 2438b23d5de9SAlexander V. Chernikov cfg = (struct numarray_cfg *)ta_state; 2439b23d5de9SAlexander V. Chernikov 2440b23d5de9SAlexander V. Chernikov old_ptr = cfg->main_ptr; 2441b23d5de9SAlexander V. Chernikov cfg->main_ptr = mi->main_ptr; 2442b23d5de9SAlexander V. Chernikov cfg->size = mi->size; 2443b23d5de9SAlexander V. Chernikov ti->state = cfg->main_ptr; 2444b23d5de9SAlexander V. Chernikov 2445b23d5de9SAlexander V. Chernikov mi->main_ptr = old_ptr; 2446b23d5de9SAlexander V. Chernikov 2447b23d5de9SAlexander V. Chernikov return (0); 2448b23d5de9SAlexander V. Chernikov } 2449b23d5de9SAlexander V. Chernikov 2450b23d5de9SAlexander V. Chernikov /* 2451b23d5de9SAlexander V. Chernikov * Free unneded array. 2452b23d5de9SAlexander V. Chernikov */ 2453b23d5de9SAlexander V. Chernikov static void 2454b23d5de9SAlexander V. Chernikov ta_flush_mod_numarray(void *ta_buf) 2455b23d5de9SAlexander V. Chernikov { 2456b23d5de9SAlexander V. Chernikov struct mod_item *mi; 2457b23d5de9SAlexander V. Chernikov 2458b23d5de9SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 2459b23d5de9SAlexander V. Chernikov if (mi->main_ptr != NULL) 2460b23d5de9SAlexander V. Chernikov free(mi->main_ptr, M_IPFW); 2461b23d5de9SAlexander V. Chernikov } 2462b23d5de9SAlexander V. Chernikov 2463b23d5de9SAlexander V. Chernikov static int 2464b23d5de9SAlexander V. Chernikov ta_dump_numarray_tentry(void *ta_state, struct table_info *ti, void *e, 2465b23d5de9SAlexander V. Chernikov ipfw_obj_tentry *tent) 2466b23d5de9SAlexander V. Chernikov { 2467b23d5de9SAlexander V. Chernikov struct numarray *na; 2468b23d5de9SAlexander V. Chernikov 2469b23d5de9SAlexander V. Chernikov na = (struct numarray *)e; 2470b23d5de9SAlexander V. Chernikov 2471b23d5de9SAlexander V. Chernikov tent->k.key = na->number; 2472b23d5de9SAlexander V. Chernikov tent->value = na->value; 2473b23d5de9SAlexander V. Chernikov 2474b23d5de9SAlexander V. Chernikov return (0); 2475b23d5de9SAlexander V. Chernikov } 2476b23d5de9SAlexander V. Chernikov 2477b23d5de9SAlexander V. Chernikov static int 2478914bffb6SAlexander V. Chernikov ta_find_numarray_tentry(void *ta_state, struct table_info *ti, 2479914bffb6SAlexander V. Chernikov ipfw_obj_tentry *tent) 2480b23d5de9SAlexander V. Chernikov { 2481b23d5de9SAlexander V. Chernikov struct numarray_cfg *cfg; 2482b23d5de9SAlexander V. Chernikov struct numarray *ri; 2483b23d5de9SAlexander V. Chernikov 2484b23d5de9SAlexander V. Chernikov cfg = (struct numarray_cfg *)ta_state; 2485b23d5de9SAlexander V. Chernikov 2486914bffb6SAlexander V. Chernikov ri = numarray_find(ti, &tent->k.key); 2487b23d5de9SAlexander V. Chernikov 2488b23d5de9SAlexander V. Chernikov if (ri != NULL) { 2489b23d5de9SAlexander V. Chernikov ta_dump_numarray_tentry(ta_state, ti, ri, tent); 2490b23d5de9SAlexander V. Chernikov return (0); 2491b23d5de9SAlexander V. Chernikov } 2492b23d5de9SAlexander V. Chernikov 2493b23d5de9SAlexander V. Chernikov return (ENOENT); 2494b23d5de9SAlexander V. Chernikov } 2495b23d5de9SAlexander V. Chernikov 2496b23d5de9SAlexander V. Chernikov static void 2497b23d5de9SAlexander V. Chernikov ta_foreach_numarray(void *ta_state, struct table_info *ti, ta_foreach_f *f, 2498b23d5de9SAlexander V. Chernikov void *arg) 2499b23d5de9SAlexander V. Chernikov { 2500b23d5de9SAlexander V. Chernikov struct numarray_cfg *cfg; 2501b23d5de9SAlexander V. Chernikov struct numarray *array; 2502b23d5de9SAlexander V. Chernikov int i; 2503b23d5de9SAlexander V. Chernikov 2504b23d5de9SAlexander V. Chernikov cfg = (struct numarray_cfg *)ta_state; 2505b23d5de9SAlexander V. Chernikov array = cfg->main_ptr; 2506b23d5de9SAlexander V. Chernikov 2507b23d5de9SAlexander V. Chernikov for (i = 0; i < cfg->used; i++) 2508b23d5de9SAlexander V. Chernikov f(&array[i], arg); 2509b23d5de9SAlexander V. Chernikov } 2510b23d5de9SAlexander V. Chernikov 2511b23d5de9SAlexander V. Chernikov struct table_algo number_array = { 2512b23d5de9SAlexander V. Chernikov .name = "number:array", 2513b23d5de9SAlexander V. Chernikov .type = IPFW_TABLE_NUMBER, 251457a1cf95SAlexander V. Chernikov .ta_buf_size = sizeof(struct ta_buf_numarray), 2515b23d5de9SAlexander V. Chernikov .init = ta_init_numarray, 2516b23d5de9SAlexander V. Chernikov .destroy = ta_destroy_numarray, 2517b23d5de9SAlexander V. Chernikov .prepare_add = ta_prepare_add_numarray, 2518b23d5de9SAlexander V. Chernikov .prepare_del = ta_prepare_add_numarray, 2519b23d5de9SAlexander V. Chernikov .add = ta_add_numarray, 2520b23d5de9SAlexander V. Chernikov .del = ta_del_numarray, 2521b23d5de9SAlexander V. Chernikov .flush_entry = ta_flush_numarray_entry, 2522b23d5de9SAlexander V. Chernikov .foreach = ta_foreach_numarray, 2523b23d5de9SAlexander V. Chernikov .dump_tentry = ta_dump_numarray_tentry, 2524b23d5de9SAlexander V. Chernikov .find_tentry = ta_find_numarray_tentry, 2525b6ee846eSAlexander V. Chernikov .has_space = ta_has_space_numarray, 2526b23d5de9SAlexander V. Chernikov .prepare_mod = ta_prepare_mod_numarray, 2527b23d5de9SAlexander V. Chernikov .fill_mod = ta_fill_mod_numarray, 2528b23d5de9SAlexander V. Chernikov .modify = ta_modify_numarray, 2529b23d5de9SAlexander V. Chernikov .flush_mod = ta_flush_mod_numarray, 2530b23d5de9SAlexander V. Chernikov }; 2531b23d5de9SAlexander V. Chernikov 2532914bffb6SAlexander V. Chernikov /* 2533914bffb6SAlexander V. Chernikov * flow:hash cmds 2534914bffb6SAlexander V. Chernikov * 2535914bffb6SAlexander V. Chernikov * 2536914bffb6SAlexander V. Chernikov * ti->data: 2537914bffb6SAlexander V. Chernikov * [inv.mask4][inv.mask6][log2hsize4][log2hsize6] 2538914bffb6SAlexander V. Chernikov * [ 8][ 8[ 8][ 8] 2539914bffb6SAlexander V. Chernikov * 2540914bffb6SAlexander V. Chernikov * inv.mask4: 32 - mask 2541914bffb6SAlexander V. Chernikov * inv.mask6: 2542914bffb6SAlexander V. Chernikov * 1) _slow lookup: mask 2543914bffb6SAlexander V. Chernikov * 2) _aligned: (128 - mask) / 8 2544914bffb6SAlexander V. Chernikov * 3) _64: 8 2545914bffb6SAlexander V. Chernikov * 2546914bffb6SAlexander V. Chernikov * 2547914bffb6SAlexander V. Chernikov * pflags: 2548b6ee846eSAlexander V. Chernikov * [hsize4][hsize6] 2549b6ee846eSAlexander V. Chernikov * [ 16][ 16] 2550914bffb6SAlexander V. Chernikov */ 2551914bffb6SAlexander V. Chernikov 2552914bffb6SAlexander V. Chernikov struct fhashentry; 2553914bffb6SAlexander V. Chernikov 2554914bffb6SAlexander V. Chernikov SLIST_HEAD(fhashbhead, fhashentry); 2555914bffb6SAlexander V. Chernikov 2556914bffb6SAlexander V. Chernikov struct fhashentry { 2557914bffb6SAlexander V. Chernikov SLIST_ENTRY(fhashentry) next; 2558914bffb6SAlexander V. Chernikov uint8_t af; 2559914bffb6SAlexander V. Chernikov uint8_t proto; 2560914bffb6SAlexander V. Chernikov uint16_t spare0; 2561914bffb6SAlexander V. Chernikov uint16_t dport; 2562914bffb6SAlexander V. Chernikov uint16_t sport; 2563914bffb6SAlexander V. Chernikov uint32_t value; 2564914bffb6SAlexander V. Chernikov uint32_t spare1; 2565914bffb6SAlexander V. Chernikov }; 2566914bffb6SAlexander V. Chernikov 2567914bffb6SAlexander V. Chernikov struct fhashentry4 { 2568914bffb6SAlexander V. Chernikov struct fhashentry e; 2569914bffb6SAlexander V. Chernikov struct in_addr dip; 2570914bffb6SAlexander V. Chernikov struct in_addr sip; 2571914bffb6SAlexander V. Chernikov }; 2572914bffb6SAlexander V. Chernikov 2573914bffb6SAlexander V. Chernikov struct fhashentry6 { 2574914bffb6SAlexander V. Chernikov struct fhashentry e; 2575914bffb6SAlexander V. Chernikov struct in6_addr dip6; 2576914bffb6SAlexander V. Chernikov struct in6_addr sip6; 2577914bffb6SAlexander V. Chernikov }; 2578914bffb6SAlexander V. Chernikov 2579914bffb6SAlexander V. Chernikov struct fhash_cfg { 2580914bffb6SAlexander V. Chernikov struct fhashbhead *head; 2581914bffb6SAlexander V. Chernikov size_t size; 2582914bffb6SAlexander V. Chernikov size_t items; 2583914bffb6SAlexander V. Chernikov struct fhashentry4 fe4; 2584914bffb6SAlexander V. Chernikov struct fhashentry6 fe6; 2585914bffb6SAlexander V. Chernikov }; 2586914bffb6SAlexander V. Chernikov 25873fe2ef91SAlexander V. Chernikov struct ta_buf_fhash { 25880bce0c23SAlexander V. Chernikov void *ent_ptr; 25890bce0c23SAlexander V. Chernikov struct fhashentry6 fe6; 25900bce0c23SAlexander V. Chernikov }; 25910bce0c23SAlexander V. Chernikov 2592914bffb6SAlexander V. Chernikov static __inline int 2593914bffb6SAlexander V. Chernikov cmp_flow_ent(struct fhashentry *a, struct fhashentry *b, size_t sz) 2594914bffb6SAlexander V. Chernikov { 2595914bffb6SAlexander V. Chernikov uint64_t *ka, *kb; 2596914bffb6SAlexander V. Chernikov 2597914bffb6SAlexander V. Chernikov ka = (uint64_t *)(&a->next + 1); 2598914bffb6SAlexander V. Chernikov kb = (uint64_t *)(&b->next + 1); 2599914bffb6SAlexander V. Chernikov 2600914bffb6SAlexander V. Chernikov if (*ka == *kb && (memcmp(a + 1, b + 1, sz) == 0)) 2601914bffb6SAlexander V. Chernikov return (1); 2602914bffb6SAlexander V. Chernikov 2603914bffb6SAlexander V. Chernikov return (0); 2604914bffb6SAlexander V. Chernikov } 2605914bffb6SAlexander V. Chernikov 2606914bffb6SAlexander V. Chernikov static __inline uint32_t 2607914bffb6SAlexander V. Chernikov hash_flow4(struct fhashentry4 *f, int hsize) 2608914bffb6SAlexander V. Chernikov { 2609914bffb6SAlexander V. Chernikov uint32_t i; 2610914bffb6SAlexander V. Chernikov 2611914bffb6SAlexander V. Chernikov i = (f->dip.s_addr) ^ (f->sip.s_addr) ^ (f->e.dport) ^ (f->e.sport); 2612914bffb6SAlexander V. Chernikov 2613914bffb6SAlexander V. Chernikov return (i % (hsize - 1)); 2614914bffb6SAlexander V. Chernikov } 2615914bffb6SAlexander V. Chernikov 2616914bffb6SAlexander V. Chernikov static __inline uint32_t 2617914bffb6SAlexander V. Chernikov hash_flow6(struct fhashentry6 *f, int hsize) 2618914bffb6SAlexander V. Chernikov { 2619914bffb6SAlexander V. Chernikov uint32_t i; 2620914bffb6SAlexander V. Chernikov 2621914bffb6SAlexander V. Chernikov i = (f->dip6.__u6_addr.__u6_addr32[2]) ^ 2622914bffb6SAlexander V. Chernikov (f->dip6.__u6_addr.__u6_addr32[3]) ^ 2623914bffb6SAlexander V. Chernikov (f->sip6.__u6_addr.__u6_addr32[2]) ^ 2624914bffb6SAlexander V. Chernikov (f->sip6.__u6_addr.__u6_addr32[3]) ^ 2625914bffb6SAlexander V. Chernikov (f->e.dport) ^ (f->e.sport); 2626914bffb6SAlexander V. Chernikov 2627914bffb6SAlexander V. Chernikov return (i % (hsize - 1)); 2628914bffb6SAlexander V. Chernikov } 2629914bffb6SAlexander V. Chernikov 2630914bffb6SAlexander V. Chernikov static uint32_t 2631914bffb6SAlexander V. Chernikov hash_flow_ent(struct fhashentry *ent, uint32_t size) 2632914bffb6SAlexander V. Chernikov { 2633914bffb6SAlexander V. Chernikov uint32_t hash; 2634914bffb6SAlexander V. Chernikov 2635914bffb6SAlexander V. Chernikov if (ent->af == AF_INET) { 2636914bffb6SAlexander V. Chernikov hash = hash_flow4((struct fhashentry4 *)ent, size); 2637914bffb6SAlexander V. Chernikov } else { 2638914bffb6SAlexander V. Chernikov hash = hash_flow6((struct fhashentry6 *)ent, size); 2639914bffb6SAlexander V. Chernikov } 2640914bffb6SAlexander V. Chernikov 2641914bffb6SAlexander V. Chernikov return (hash); 2642914bffb6SAlexander V. Chernikov } 2643914bffb6SAlexander V. Chernikov 2644914bffb6SAlexander V. Chernikov static int 2645914bffb6SAlexander V. Chernikov ta_lookup_fhash(struct table_info *ti, void *key, uint32_t keylen, 2646914bffb6SAlexander V. Chernikov uint32_t *val) 2647914bffb6SAlexander V. Chernikov { 2648914bffb6SAlexander V. Chernikov struct fhashbhead *head; 2649914bffb6SAlexander V. Chernikov struct fhashentry *ent; 2650914bffb6SAlexander V. Chernikov struct fhashentry4 *m4; 2651914bffb6SAlexander V. Chernikov struct ipfw_flow_id *id; 2652914bffb6SAlexander V. Chernikov uint16_t hash, hsize; 2653914bffb6SAlexander V. Chernikov 2654914bffb6SAlexander V. Chernikov id = (struct ipfw_flow_id *)key; 2655914bffb6SAlexander V. Chernikov head = (struct fhashbhead *)ti->state; 2656914bffb6SAlexander V. Chernikov hsize = ti->data; 2657914bffb6SAlexander V. Chernikov m4 = (struct fhashentry4 *)ti->xstate; 2658914bffb6SAlexander V. Chernikov 2659914bffb6SAlexander V. Chernikov if (id->addr_type == 4) { 2660914bffb6SAlexander V. Chernikov struct fhashentry4 f; 2661914bffb6SAlexander V. Chernikov 2662914bffb6SAlexander V. Chernikov /* Copy hash mask */ 2663914bffb6SAlexander V. Chernikov f = *m4; 2664914bffb6SAlexander V. Chernikov 2665914bffb6SAlexander V. Chernikov f.dip.s_addr &= id->dst_ip; 2666914bffb6SAlexander V. Chernikov f.sip.s_addr &= id->src_ip; 2667914bffb6SAlexander V. Chernikov f.e.dport &= id->dst_port; 2668914bffb6SAlexander V. Chernikov f.e.sport &= id->src_port; 2669914bffb6SAlexander V. Chernikov f.e.proto &= id->proto; 2670914bffb6SAlexander V. Chernikov hash = hash_flow4(&f, hsize); 2671914bffb6SAlexander V. Chernikov SLIST_FOREACH(ent, &head[hash], next) { 2672914bffb6SAlexander V. Chernikov if (cmp_flow_ent(ent, &f.e, 2 * 4) != 0) { 2673914bffb6SAlexander V. Chernikov *val = ent->value; 2674914bffb6SAlexander V. Chernikov return (1); 2675914bffb6SAlexander V. Chernikov } 2676914bffb6SAlexander V. Chernikov } 2677914bffb6SAlexander V. Chernikov } else if (id->addr_type == 6) { 2678914bffb6SAlexander V. Chernikov struct fhashentry6 f; 2679914bffb6SAlexander V. Chernikov uint64_t *fp, *idp; 2680914bffb6SAlexander V. Chernikov 2681914bffb6SAlexander V. Chernikov /* Copy hash mask */ 2682914bffb6SAlexander V. Chernikov f = *((struct fhashentry6 *)(m4 + 1)); 2683914bffb6SAlexander V. Chernikov 2684914bffb6SAlexander V. Chernikov /* Handle lack of __u6_addr.__u6_addr64 */ 2685914bffb6SAlexander V. Chernikov fp = (uint64_t *)&f.dip6; 2686914bffb6SAlexander V. Chernikov idp = (uint64_t *)&id->dst_ip6; 2687914bffb6SAlexander V. Chernikov /* src IPv6 is stored after dst IPv6 */ 2688914bffb6SAlexander V. Chernikov *fp++ &= *idp++; 2689914bffb6SAlexander V. Chernikov *fp++ &= *idp++; 2690914bffb6SAlexander V. Chernikov *fp++ &= *idp++; 2691914bffb6SAlexander V. Chernikov *fp &= *idp; 2692914bffb6SAlexander V. Chernikov f.e.dport &= id->dst_port; 2693914bffb6SAlexander V. Chernikov f.e.sport &= id->src_port; 2694914bffb6SAlexander V. Chernikov f.e.proto &= id->proto; 2695914bffb6SAlexander V. Chernikov hash = hash_flow6(&f, hsize); 2696914bffb6SAlexander V. Chernikov SLIST_FOREACH(ent, &head[hash], next) { 2697914bffb6SAlexander V. Chernikov if (cmp_flow_ent(ent, &f.e, 2 * 16) != 0) { 2698914bffb6SAlexander V. Chernikov *val = ent->value; 2699914bffb6SAlexander V. Chernikov return (1); 2700914bffb6SAlexander V. Chernikov } 2701914bffb6SAlexander V. Chernikov } 2702914bffb6SAlexander V. Chernikov } 2703914bffb6SAlexander V. Chernikov 2704914bffb6SAlexander V. Chernikov return (0); 2705914bffb6SAlexander V. Chernikov } 2706914bffb6SAlexander V. Chernikov 2707914bffb6SAlexander V. Chernikov /* 2708914bffb6SAlexander V. Chernikov * New table. 2709914bffb6SAlexander V. Chernikov */ 2710914bffb6SAlexander V. Chernikov static int 2711914bffb6SAlexander V. Chernikov ta_init_fhash(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti, 2712914bffb6SAlexander V. Chernikov char *data, uint8_t tflags) 2713914bffb6SAlexander V. Chernikov { 2714914bffb6SAlexander V. Chernikov int i; 2715914bffb6SAlexander V. Chernikov struct fhash_cfg *cfg; 2716914bffb6SAlexander V. Chernikov struct fhashentry4 *fe4; 2717914bffb6SAlexander V. Chernikov struct fhashentry6 *fe6; 2718914bffb6SAlexander V. Chernikov 2719914bffb6SAlexander V. Chernikov cfg = malloc(sizeof(struct fhash_cfg), M_IPFW, M_WAITOK | M_ZERO); 2720914bffb6SAlexander V. Chernikov 2721914bffb6SAlexander V. Chernikov cfg->size = 512; 2722914bffb6SAlexander V. Chernikov 2723914bffb6SAlexander V. Chernikov cfg->head = malloc(sizeof(struct fhashbhead) * cfg->size, M_IPFW, 2724914bffb6SAlexander V. Chernikov M_WAITOK | M_ZERO); 2725914bffb6SAlexander V. Chernikov for (i = 0; i < cfg->size; i++) 2726914bffb6SAlexander V. Chernikov SLIST_INIT(&cfg->head[i]); 2727914bffb6SAlexander V. Chernikov 2728914bffb6SAlexander V. Chernikov /* Fill in fe masks based on @tflags */ 2729914bffb6SAlexander V. Chernikov fe4 = &cfg->fe4; 2730914bffb6SAlexander V. Chernikov fe6 = &cfg->fe6; 2731914bffb6SAlexander V. Chernikov if (tflags & IPFW_TFFLAG_SRCIP) { 2732914bffb6SAlexander V. Chernikov memset(&fe4->sip, 0xFF, sizeof(fe4->sip)); 2733914bffb6SAlexander V. Chernikov memset(&fe6->sip6, 0xFF, sizeof(fe6->sip6)); 2734914bffb6SAlexander V. Chernikov } 2735914bffb6SAlexander V. Chernikov if (tflags & IPFW_TFFLAG_DSTIP) { 2736914bffb6SAlexander V. Chernikov memset(&fe4->dip, 0xFF, sizeof(fe4->dip)); 2737914bffb6SAlexander V. Chernikov memset(&fe6->dip6, 0xFF, sizeof(fe6->dip6)); 2738914bffb6SAlexander V. Chernikov } 2739914bffb6SAlexander V. Chernikov if (tflags & IPFW_TFFLAG_SRCPORT) { 2740914bffb6SAlexander V. Chernikov memset(&fe4->e.sport, 0xFF, sizeof(fe4->e.sport)); 2741914bffb6SAlexander V. Chernikov memset(&fe6->e.sport, 0xFF, sizeof(fe6->e.sport)); 2742914bffb6SAlexander V. Chernikov } 2743914bffb6SAlexander V. Chernikov if (tflags & IPFW_TFFLAG_DSTPORT) { 2744914bffb6SAlexander V. Chernikov memset(&fe4->e.dport, 0xFF, sizeof(fe4->e.dport)); 2745914bffb6SAlexander V. Chernikov memset(&fe6->e.dport, 0xFF, sizeof(fe6->e.dport)); 2746914bffb6SAlexander V. Chernikov } 2747914bffb6SAlexander V. Chernikov if (tflags & IPFW_TFFLAG_PROTO) { 2748914bffb6SAlexander V. Chernikov memset(&fe4->e.proto, 0xFF, sizeof(fe4->e.proto)); 2749914bffb6SAlexander V. Chernikov memset(&fe6->e.proto, 0xFF, sizeof(fe6->e.proto)); 2750914bffb6SAlexander V. Chernikov } 2751914bffb6SAlexander V. Chernikov 2752914bffb6SAlexander V. Chernikov fe4->e.af = AF_INET; 2753914bffb6SAlexander V. Chernikov fe6->e.af = AF_INET6; 2754914bffb6SAlexander V. Chernikov 2755914bffb6SAlexander V. Chernikov *ta_state = cfg; 2756914bffb6SAlexander V. Chernikov ti->state = cfg->head; 2757914bffb6SAlexander V. Chernikov ti->xstate = &cfg->fe4; 2758914bffb6SAlexander V. Chernikov ti->data = cfg->size; 2759914bffb6SAlexander V. Chernikov ti->lookup = ta_lookup_fhash; 2760914bffb6SAlexander V. Chernikov 2761914bffb6SAlexander V. Chernikov return (0); 2762914bffb6SAlexander V. Chernikov } 2763914bffb6SAlexander V. Chernikov 2764914bffb6SAlexander V. Chernikov static void 2765914bffb6SAlexander V. Chernikov ta_destroy_fhash(void *ta_state, struct table_info *ti) 2766914bffb6SAlexander V. Chernikov { 2767914bffb6SAlexander V. Chernikov struct fhash_cfg *cfg; 2768914bffb6SAlexander V. Chernikov struct fhashentry *ent, *ent_next; 2769914bffb6SAlexander V. Chernikov int i; 2770914bffb6SAlexander V. Chernikov 2771914bffb6SAlexander V. Chernikov cfg = (struct fhash_cfg *)ta_state; 2772914bffb6SAlexander V. Chernikov 2773914bffb6SAlexander V. Chernikov for (i = 0; i < cfg->size; i++) 2774914bffb6SAlexander V. Chernikov SLIST_FOREACH_SAFE(ent, &cfg->head[i], next, ent_next) 2775914bffb6SAlexander V. Chernikov free(ent, M_IPFW_TBL); 2776914bffb6SAlexander V. Chernikov 2777914bffb6SAlexander V. Chernikov free(cfg->head, M_IPFW); 2778914bffb6SAlexander V. Chernikov free(cfg, M_IPFW); 2779914bffb6SAlexander V. Chernikov } 2780914bffb6SAlexander V. Chernikov 2781914bffb6SAlexander V. Chernikov static int 2782914bffb6SAlexander V. Chernikov ta_dump_fhash_tentry(void *ta_state, struct table_info *ti, void *e, 2783914bffb6SAlexander V. Chernikov ipfw_obj_tentry *tent) 2784914bffb6SAlexander V. Chernikov { 2785914bffb6SAlexander V. Chernikov struct fhash_cfg *cfg; 2786914bffb6SAlexander V. Chernikov struct fhashentry *ent; 2787914bffb6SAlexander V. Chernikov struct fhashentry4 *fe4; 2788914bffb6SAlexander V. Chernikov struct fhashentry6 *fe6; 2789914bffb6SAlexander V. Chernikov struct tflow_entry *tfe; 2790914bffb6SAlexander V. Chernikov 2791914bffb6SAlexander V. Chernikov cfg = (struct fhash_cfg *)ta_state; 2792914bffb6SAlexander V. Chernikov ent = (struct fhashentry *)e; 2793914bffb6SAlexander V. Chernikov tfe = &tent->k.flow; 2794914bffb6SAlexander V. Chernikov 2795914bffb6SAlexander V. Chernikov tfe->af = ent->af; 2796914bffb6SAlexander V. Chernikov tfe->proto = ent->proto; 2797914bffb6SAlexander V. Chernikov tfe->dport = htons(ent->dport); 2798914bffb6SAlexander V. Chernikov tfe->sport = htons(ent->sport); 2799914bffb6SAlexander V. Chernikov tent->value = ent->value; 2800914bffb6SAlexander V. Chernikov tent->subtype = ent->af; 2801914bffb6SAlexander V. Chernikov 2802914bffb6SAlexander V. Chernikov if (ent->af == AF_INET) { 2803914bffb6SAlexander V. Chernikov fe4 = (struct fhashentry4 *)ent; 2804914bffb6SAlexander V. Chernikov tfe->a.a4.sip.s_addr = htonl(fe4->sip.s_addr); 2805914bffb6SAlexander V. Chernikov tfe->a.a4.dip.s_addr = htonl(fe4->dip.s_addr); 2806914bffb6SAlexander V. Chernikov tent->masklen = 32; 2807914bffb6SAlexander V. Chernikov #ifdef INET6 2808914bffb6SAlexander V. Chernikov } else { 2809914bffb6SAlexander V. Chernikov fe6 = (struct fhashentry6 *)ent; 2810914bffb6SAlexander V. Chernikov tfe->a.a6.sip6 = fe6->sip6; 2811914bffb6SAlexander V. Chernikov tfe->a.a6.dip6 = fe6->dip6; 2812914bffb6SAlexander V. Chernikov tent->masklen = 128; 2813914bffb6SAlexander V. Chernikov #endif 2814914bffb6SAlexander V. Chernikov } 2815914bffb6SAlexander V. Chernikov 2816914bffb6SAlexander V. Chernikov return (0); 2817914bffb6SAlexander V. Chernikov } 2818914bffb6SAlexander V. Chernikov 2819914bffb6SAlexander V. Chernikov static int 2820914bffb6SAlexander V. Chernikov tei_to_fhash_ent(struct tentry_info *tei, struct fhashentry *ent) 2821914bffb6SAlexander V. Chernikov { 2822914bffb6SAlexander V. Chernikov struct fhashentry4 *fe4; 2823914bffb6SAlexander V. Chernikov struct fhashentry6 *fe6; 2824914bffb6SAlexander V. Chernikov struct tflow_entry *tfe; 2825914bffb6SAlexander V. Chernikov 2826914bffb6SAlexander V. Chernikov tfe = (struct tflow_entry *)tei->paddr; 2827914bffb6SAlexander V. Chernikov 2828914bffb6SAlexander V. Chernikov ent->af = tei->subtype; 2829914bffb6SAlexander V. Chernikov ent->proto = tfe->proto; 2830914bffb6SAlexander V. Chernikov ent->value = tei->value; 2831914bffb6SAlexander V. Chernikov ent->dport = ntohs(tfe->dport); 2832914bffb6SAlexander V. Chernikov ent->sport = ntohs(tfe->sport); 2833914bffb6SAlexander V. Chernikov 2834914bffb6SAlexander V. Chernikov if (tei->subtype == AF_INET) { 2835914bffb6SAlexander V. Chernikov #ifdef INET 2836914bffb6SAlexander V. Chernikov fe4 = (struct fhashentry4 *)ent; 2837914bffb6SAlexander V. Chernikov fe4->sip.s_addr = ntohl(tfe->a.a4.sip.s_addr); 2838914bffb6SAlexander V. Chernikov fe4->dip.s_addr = ntohl(tfe->a.a4.dip.s_addr); 2839914bffb6SAlexander V. Chernikov #endif 2840914bffb6SAlexander V. Chernikov #ifdef INET6 2841914bffb6SAlexander V. Chernikov } else if (tei->subtype == AF_INET6) { 2842914bffb6SAlexander V. Chernikov fe6 = (struct fhashentry6 *)ent; 2843914bffb6SAlexander V. Chernikov fe6->sip6 = tfe->a.a6.sip6; 2844914bffb6SAlexander V. Chernikov fe6->dip6 = tfe->a.a6.dip6; 2845914bffb6SAlexander V. Chernikov #endif 2846914bffb6SAlexander V. Chernikov } else { 2847914bffb6SAlexander V. Chernikov /* Unknown CIDR type */ 2848914bffb6SAlexander V. Chernikov return (EINVAL); 2849914bffb6SAlexander V. Chernikov } 2850914bffb6SAlexander V. Chernikov 2851914bffb6SAlexander V. Chernikov return (0); 2852914bffb6SAlexander V. Chernikov } 2853914bffb6SAlexander V. Chernikov 2854914bffb6SAlexander V. Chernikov 2855914bffb6SAlexander V. Chernikov static int 2856914bffb6SAlexander V. Chernikov ta_find_fhash_tentry(void *ta_state, struct table_info *ti, 2857914bffb6SAlexander V. Chernikov ipfw_obj_tentry *tent) 2858914bffb6SAlexander V. Chernikov { 2859914bffb6SAlexander V. Chernikov struct fhash_cfg *cfg; 2860914bffb6SAlexander V. Chernikov struct fhashbhead *head; 2861914bffb6SAlexander V. Chernikov struct fhashentry *ent, *tmp; 2862914bffb6SAlexander V. Chernikov struct fhashentry6 fe6; 2863914bffb6SAlexander V. Chernikov struct tentry_info tei; 2864914bffb6SAlexander V. Chernikov int error; 2865914bffb6SAlexander V. Chernikov uint32_t hash; 2866914bffb6SAlexander V. Chernikov size_t sz; 2867914bffb6SAlexander V. Chernikov 2868914bffb6SAlexander V. Chernikov cfg = (struct fhash_cfg *)ta_state; 2869914bffb6SAlexander V. Chernikov 2870914bffb6SAlexander V. Chernikov ent = &fe6.e; 2871914bffb6SAlexander V. Chernikov 2872914bffb6SAlexander V. Chernikov memset(&fe6, 0, sizeof(fe6)); 2873914bffb6SAlexander V. Chernikov memset(&tei, 0, sizeof(tei)); 2874914bffb6SAlexander V. Chernikov 2875914bffb6SAlexander V. Chernikov tei.paddr = &tent->k.flow; 2876914bffb6SAlexander V. Chernikov tei.subtype = tent->subtype; 2877914bffb6SAlexander V. Chernikov 2878914bffb6SAlexander V. Chernikov if ((error = tei_to_fhash_ent(&tei, ent)) != 0) 2879914bffb6SAlexander V. Chernikov return (error); 2880914bffb6SAlexander V. Chernikov 2881914bffb6SAlexander V. Chernikov head = cfg->head; 2882914bffb6SAlexander V. Chernikov hash = hash_flow_ent(ent, cfg->size); 2883914bffb6SAlexander V. Chernikov 2884914bffb6SAlexander V. Chernikov if (tei.subtype == AF_INET) 2885914bffb6SAlexander V. Chernikov sz = 2 * sizeof(struct in_addr); 2886914bffb6SAlexander V. Chernikov else 2887914bffb6SAlexander V. Chernikov sz = 2 * sizeof(struct in6_addr); 2888914bffb6SAlexander V. Chernikov 2889914bffb6SAlexander V. Chernikov /* Check for existence */ 2890914bffb6SAlexander V. Chernikov SLIST_FOREACH(tmp, &head[hash], next) { 2891914bffb6SAlexander V. Chernikov if (cmp_flow_ent(tmp, ent, sz) != 0) { 2892914bffb6SAlexander V. Chernikov ta_dump_fhash_tentry(ta_state, ti, tmp, tent); 2893914bffb6SAlexander V. Chernikov return (0); 2894914bffb6SAlexander V. Chernikov } 2895914bffb6SAlexander V. Chernikov } 2896914bffb6SAlexander V. Chernikov 2897914bffb6SAlexander V. Chernikov return (ENOENT); 2898914bffb6SAlexander V. Chernikov } 2899914bffb6SAlexander V. Chernikov 2900914bffb6SAlexander V. Chernikov static void 2901914bffb6SAlexander V. Chernikov ta_foreach_fhash(void *ta_state, struct table_info *ti, ta_foreach_f *f, 2902914bffb6SAlexander V. Chernikov void *arg) 2903914bffb6SAlexander V. Chernikov { 2904914bffb6SAlexander V. Chernikov struct fhash_cfg *cfg; 2905914bffb6SAlexander V. Chernikov struct fhashentry *ent, *ent_next; 2906914bffb6SAlexander V. Chernikov int i; 2907914bffb6SAlexander V. Chernikov 2908914bffb6SAlexander V. Chernikov cfg = (struct fhash_cfg *)ta_state; 2909914bffb6SAlexander V. Chernikov 2910914bffb6SAlexander V. Chernikov for (i = 0; i < cfg->size; i++) 2911914bffb6SAlexander V. Chernikov SLIST_FOREACH_SAFE(ent, &cfg->head[i], next, ent_next) 2912914bffb6SAlexander V. Chernikov f(ent, arg); 2913914bffb6SAlexander V. Chernikov } 2914914bffb6SAlexander V. Chernikov 2915914bffb6SAlexander V. Chernikov static int 2916914bffb6SAlexander V. Chernikov ta_prepare_add_fhash(struct ip_fw_chain *ch, struct tentry_info *tei, 2917914bffb6SAlexander V. Chernikov void *ta_buf) 2918914bffb6SAlexander V. Chernikov { 2919914bffb6SAlexander V. Chernikov struct ta_buf_fhash *tb; 2920914bffb6SAlexander V. Chernikov struct fhashentry *ent; 2921914bffb6SAlexander V. Chernikov size_t sz; 2922914bffb6SAlexander V. Chernikov int error; 2923914bffb6SAlexander V. Chernikov 2924914bffb6SAlexander V. Chernikov tb = (struct ta_buf_fhash *)ta_buf; 2925914bffb6SAlexander V. Chernikov 2926914bffb6SAlexander V. Chernikov if (tei->subtype == AF_INET) 2927914bffb6SAlexander V. Chernikov sz = sizeof(struct fhashentry4); 2928914bffb6SAlexander V. Chernikov else if (tei->subtype == AF_INET6) 2929914bffb6SAlexander V. Chernikov sz = sizeof(struct fhashentry6); 2930914bffb6SAlexander V. Chernikov else 2931914bffb6SAlexander V. Chernikov return (EINVAL); 2932914bffb6SAlexander V. Chernikov 2933914bffb6SAlexander V. Chernikov ent = malloc(sz, M_IPFW_TBL, M_WAITOK | M_ZERO); 2934914bffb6SAlexander V. Chernikov 2935914bffb6SAlexander V. Chernikov error = tei_to_fhash_ent(tei, ent); 2936914bffb6SAlexander V. Chernikov if (error != 0) { 2937914bffb6SAlexander V. Chernikov free(ent, M_IPFW_TBL); 2938914bffb6SAlexander V. Chernikov return (error); 2939914bffb6SAlexander V. Chernikov } 2940914bffb6SAlexander V. Chernikov tb->ent_ptr = ent; 2941914bffb6SAlexander V. Chernikov 2942914bffb6SAlexander V. Chernikov return (0); 2943914bffb6SAlexander V. Chernikov } 2944914bffb6SAlexander V. Chernikov 2945914bffb6SAlexander V. Chernikov static int 2946914bffb6SAlexander V. Chernikov ta_add_fhash(void *ta_state, struct table_info *ti, struct tentry_info *tei, 2947b6ee846eSAlexander V. Chernikov void *ta_buf, uint32_t *pnum) 2948914bffb6SAlexander V. Chernikov { 2949914bffb6SAlexander V. Chernikov struct fhash_cfg *cfg; 2950914bffb6SAlexander V. Chernikov struct fhashbhead *head; 2951914bffb6SAlexander V. Chernikov struct fhashentry *ent, *tmp; 2952914bffb6SAlexander V. Chernikov struct ta_buf_fhash *tb; 2953914bffb6SAlexander V. Chernikov int exists; 2954648e8380SAlexander V. Chernikov uint32_t hash, value; 2955914bffb6SAlexander V. Chernikov size_t sz; 2956914bffb6SAlexander V. Chernikov 2957914bffb6SAlexander V. Chernikov cfg = (struct fhash_cfg *)ta_state; 2958914bffb6SAlexander V. Chernikov tb = (struct ta_buf_fhash *)ta_buf; 2959914bffb6SAlexander V. Chernikov ent = (struct fhashentry *)tb->ent_ptr; 2960914bffb6SAlexander V. Chernikov exists = 0; 2961914bffb6SAlexander V. Chernikov 2962914bffb6SAlexander V. Chernikov head = cfg->head; 2963914bffb6SAlexander V. Chernikov hash = hash_flow_ent(ent, cfg->size); 2964914bffb6SAlexander V. Chernikov 2965914bffb6SAlexander V. Chernikov if (tei->subtype == AF_INET) 2966914bffb6SAlexander V. Chernikov sz = 2 * sizeof(struct in_addr); 2967914bffb6SAlexander V. Chernikov else 2968914bffb6SAlexander V. Chernikov sz = 2 * sizeof(struct in6_addr); 2969914bffb6SAlexander V. Chernikov 2970914bffb6SAlexander V. Chernikov /* Check for existence */ 2971914bffb6SAlexander V. Chernikov SLIST_FOREACH(tmp, &head[hash], next) { 2972914bffb6SAlexander V. Chernikov if (cmp_flow_ent(tmp, ent, sz) != 0) { 2973914bffb6SAlexander V. Chernikov exists = 1; 2974914bffb6SAlexander V. Chernikov break; 2975914bffb6SAlexander V. Chernikov } 2976914bffb6SAlexander V. Chernikov } 2977914bffb6SAlexander V. Chernikov 2978914bffb6SAlexander V. Chernikov if (exists == 1) { 2979914bffb6SAlexander V. Chernikov if ((tei->flags & TEI_FLAGS_UPDATE) == 0) 2980914bffb6SAlexander V. Chernikov return (EEXIST); 2981914bffb6SAlexander V. Chernikov /* Record already exists. Update value if we're asked to */ 2982648e8380SAlexander V. Chernikov /* Exchange values between tmp and @tei */ 2983648e8380SAlexander V. Chernikov value = tmp->value; 2984914bffb6SAlexander V. Chernikov tmp->value = tei->value; 2985648e8380SAlexander V. Chernikov tei->value = value; 2986914bffb6SAlexander V. Chernikov /* Indicate that update has happened instead of addition */ 2987914bffb6SAlexander V. Chernikov tei->flags |= TEI_FLAGS_UPDATED; 2988914bffb6SAlexander V. Chernikov *pnum = 0; 2989914bffb6SAlexander V. Chernikov } else { 29904c0c07a5SAlexander V. Chernikov if ((tei->flags & TEI_FLAGS_DONTADD) != 0) 29914c0c07a5SAlexander V. Chernikov return (EFBIG); 29924c0c07a5SAlexander V. Chernikov 2993914bffb6SAlexander V. Chernikov SLIST_INSERT_HEAD(&head[hash], ent, next); 2994914bffb6SAlexander V. Chernikov tb->ent_ptr = NULL; 2995914bffb6SAlexander V. Chernikov *pnum = 1; 2996914bffb6SAlexander V. Chernikov 2997914bffb6SAlexander V. Chernikov /* Update counters and check if we need to grow hash */ 2998914bffb6SAlexander V. Chernikov cfg->items++; 2999914bffb6SAlexander V. Chernikov } 3000914bffb6SAlexander V. Chernikov 3001914bffb6SAlexander V. Chernikov return (0); 3002914bffb6SAlexander V. Chernikov } 3003914bffb6SAlexander V. Chernikov 3004914bffb6SAlexander V. Chernikov static int 3005914bffb6SAlexander V. Chernikov ta_prepare_del_fhash(struct ip_fw_chain *ch, struct tentry_info *tei, 3006914bffb6SAlexander V. Chernikov void *ta_buf) 3007914bffb6SAlexander V. Chernikov { 3008914bffb6SAlexander V. Chernikov struct ta_buf_fhash *tb; 3009914bffb6SAlexander V. Chernikov 3010914bffb6SAlexander V. Chernikov tb = (struct ta_buf_fhash *)ta_buf; 3011914bffb6SAlexander V. Chernikov 3012914bffb6SAlexander V. Chernikov return (tei_to_fhash_ent(tei, &tb->fe6.e)); 3013914bffb6SAlexander V. Chernikov } 3014914bffb6SAlexander V. Chernikov 3015914bffb6SAlexander V. Chernikov static int 3016914bffb6SAlexander V. Chernikov ta_del_fhash(void *ta_state, struct table_info *ti, struct tentry_info *tei, 3017b6ee846eSAlexander V. Chernikov void *ta_buf, uint32_t *pnum) 3018914bffb6SAlexander V. Chernikov { 3019914bffb6SAlexander V. Chernikov struct fhash_cfg *cfg; 3020914bffb6SAlexander V. Chernikov struct fhashbhead *head; 3021914bffb6SAlexander V. Chernikov struct fhashentry *ent, *tmp; 3022914bffb6SAlexander V. Chernikov struct ta_buf_fhash *tb; 3023914bffb6SAlexander V. Chernikov uint32_t hash; 3024914bffb6SAlexander V. Chernikov size_t sz; 3025914bffb6SAlexander V. Chernikov 3026914bffb6SAlexander V. Chernikov cfg = (struct fhash_cfg *)ta_state; 3027914bffb6SAlexander V. Chernikov tb = (struct ta_buf_fhash *)ta_buf; 3028914bffb6SAlexander V. Chernikov ent = &tb->fe6.e; 3029914bffb6SAlexander V. Chernikov 3030914bffb6SAlexander V. Chernikov head = cfg->head; 3031914bffb6SAlexander V. Chernikov hash = hash_flow_ent(ent, cfg->size); 3032914bffb6SAlexander V. Chernikov 3033914bffb6SAlexander V. Chernikov if (tei->subtype == AF_INET) 3034914bffb6SAlexander V. Chernikov sz = 2 * sizeof(struct in_addr); 3035914bffb6SAlexander V. Chernikov else 3036914bffb6SAlexander V. Chernikov sz = 2 * sizeof(struct in6_addr); 3037914bffb6SAlexander V. Chernikov 3038914bffb6SAlexander V. Chernikov /* Check for existence */ 3039914bffb6SAlexander V. Chernikov SLIST_FOREACH(tmp, &head[hash], next) { 3040648e8380SAlexander V. Chernikov if (cmp_flow_ent(tmp, ent, sz) == 0) 3041648e8380SAlexander V. Chernikov continue; 3042648e8380SAlexander V. Chernikov 3043914bffb6SAlexander V. Chernikov SLIST_REMOVE(&head[hash], tmp, fhashentry, next); 3044648e8380SAlexander V. Chernikov tei->value = tmp->value; 3045914bffb6SAlexander V. Chernikov *pnum = 1; 3046914bffb6SAlexander V. Chernikov cfg->items--; 3047648e8380SAlexander V. Chernikov tb->ent_ptr = tmp; 3048914bffb6SAlexander V. Chernikov return (0); 3049914bffb6SAlexander V. Chernikov } 3050914bffb6SAlexander V. Chernikov 3051914bffb6SAlexander V. Chernikov return (ENOENT); 3052914bffb6SAlexander V. Chernikov } 3053914bffb6SAlexander V. Chernikov 3054914bffb6SAlexander V. Chernikov static void 3055914bffb6SAlexander V. Chernikov ta_flush_fhash_entry(struct ip_fw_chain *ch, struct tentry_info *tei, 3056914bffb6SAlexander V. Chernikov void *ta_buf) 3057914bffb6SAlexander V. Chernikov { 3058914bffb6SAlexander V. Chernikov struct ta_buf_fhash *tb; 3059914bffb6SAlexander V. Chernikov 3060914bffb6SAlexander V. Chernikov tb = (struct ta_buf_fhash *)ta_buf; 3061914bffb6SAlexander V. Chernikov 3062914bffb6SAlexander V. Chernikov if (tb->ent_ptr != NULL) 3063914bffb6SAlexander V. Chernikov free(tb->ent_ptr, M_IPFW_TBL); 3064914bffb6SAlexander V. Chernikov } 3065914bffb6SAlexander V. Chernikov 3066914bffb6SAlexander V. Chernikov /* 3067914bffb6SAlexander V. Chernikov * Hash growing callbacks. 3068914bffb6SAlexander V. Chernikov */ 3069914bffb6SAlexander V. Chernikov 3070b6ee846eSAlexander V. Chernikov static int 3071b6ee846eSAlexander V. Chernikov ta_has_space_fhash(void *ta_state, struct table_info *ti, uint32_t count, 3072b6ee846eSAlexander V. Chernikov uint64_t *pflags) 3073b6ee846eSAlexander V. Chernikov { 3074b6ee846eSAlexander V. Chernikov struct fhash_cfg *cfg; 3075b6ee846eSAlexander V. Chernikov 3076b6ee846eSAlexander V. Chernikov cfg = (struct fhash_cfg *)ta_state; 3077b6ee846eSAlexander V. Chernikov 3078b6ee846eSAlexander V. Chernikov if (cfg->items > cfg->size && cfg->size < 65536) { 3079b6ee846eSAlexander V. Chernikov *pflags = cfg->size * 2; 3080b6ee846eSAlexander V. Chernikov return (0); 3081b6ee846eSAlexander V. Chernikov } 3082b6ee846eSAlexander V. Chernikov 3083b6ee846eSAlexander V. Chernikov return (1); 3084b6ee846eSAlexander V. Chernikov } 3085b6ee846eSAlexander V. Chernikov 3086914bffb6SAlexander V. Chernikov /* 3087914bffb6SAlexander V. Chernikov * Allocate new, larger fhash. 3088914bffb6SAlexander V. Chernikov */ 3089914bffb6SAlexander V. Chernikov static int 3090914bffb6SAlexander V. Chernikov ta_prepare_mod_fhash(void *ta_buf, uint64_t *pflags) 3091914bffb6SAlexander V. Chernikov { 3092914bffb6SAlexander V. Chernikov struct mod_item *mi; 3093914bffb6SAlexander V. Chernikov struct fhashbhead *head; 3094914bffb6SAlexander V. Chernikov int i; 3095914bffb6SAlexander V. Chernikov 3096914bffb6SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 3097914bffb6SAlexander V. Chernikov 3098914bffb6SAlexander V. Chernikov memset(mi, 0, sizeof(struct mod_item)); 3099914bffb6SAlexander V. Chernikov mi->size = *pflags; 3100914bffb6SAlexander V. Chernikov head = malloc(sizeof(struct fhashbhead) * mi->size, M_IPFW, 3101914bffb6SAlexander V. Chernikov M_WAITOK | M_ZERO); 3102914bffb6SAlexander V. Chernikov for (i = 0; i < mi->size; i++) 3103914bffb6SAlexander V. Chernikov SLIST_INIT(&head[i]); 3104914bffb6SAlexander V. Chernikov 3105914bffb6SAlexander V. Chernikov mi->main_ptr = head; 3106914bffb6SAlexander V. Chernikov 3107914bffb6SAlexander V. Chernikov return (0); 3108914bffb6SAlexander V. Chernikov } 3109914bffb6SAlexander V. Chernikov 3110914bffb6SAlexander V. Chernikov /* 3111914bffb6SAlexander V. Chernikov * Copy data from old runtime array to new one. 3112914bffb6SAlexander V. Chernikov */ 3113914bffb6SAlexander V. Chernikov static int 3114914bffb6SAlexander V. Chernikov ta_fill_mod_fhash(void *ta_state, struct table_info *ti, void *ta_buf, 3115914bffb6SAlexander V. Chernikov uint64_t *pflags) 3116914bffb6SAlexander V. Chernikov { 3117914bffb6SAlexander V. Chernikov 3118914bffb6SAlexander V. Chernikov /* In is not possible to do rehash if we're not holidng WLOCK. */ 3119914bffb6SAlexander V. Chernikov return (0); 3120914bffb6SAlexander V. Chernikov } 3121914bffb6SAlexander V. Chernikov 3122914bffb6SAlexander V. Chernikov /* 3123914bffb6SAlexander V. Chernikov * Switch old & new arrays. 3124914bffb6SAlexander V. Chernikov */ 3125914bffb6SAlexander V. Chernikov static int 3126914bffb6SAlexander V. Chernikov ta_modify_fhash(void *ta_state, struct table_info *ti, void *ta_buf, 3127914bffb6SAlexander V. Chernikov uint64_t pflags) 3128914bffb6SAlexander V. Chernikov { 3129914bffb6SAlexander V. Chernikov struct mod_item *mi; 3130914bffb6SAlexander V. Chernikov struct fhash_cfg *cfg; 3131914bffb6SAlexander V. Chernikov struct fhashbhead *old_head, *new_head; 3132914bffb6SAlexander V. Chernikov struct fhashentry *ent, *ent_next; 3133914bffb6SAlexander V. Chernikov int i; 3134914bffb6SAlexander V. Chernikov uint32_t nhash; 3135914bffb6SAlexander V. Chernikov size_t old_size; 3136914bffb6SAlexander V. Chernikov 3137914bffb6SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 3138914bffb6SAlexander V. Chernikov cfg = (struct fhash_cfg *)ta_state; 3139914bffb6SAlexander V. Chernikov 3140914bffb6SAlexander V. Chernikov /* Check which hash we need to grow and do we still need that */ 3141914bffb6SAlexander V. Chernikov old_size = cfg->size; 3142914bffb6SAlexander V. Chernikov old_head = ti->state; 3143914bffb6SAlexander V. Chernikov 3144914bffb6SAlexander V. Chernikov if (old_size >= mi->size) 3145914bffb6SAlexander V. Chernikov return (0); 3146914bffb6SAlexander V. Chernikov 3147914bffb6SAlexander V. Chernikov new_head = (struct fhashbhead *)mi->main_ptr; 3148914bffb6SAlexander V. Chernikov for (i = 0; i < old_size; i++) { 3149914bffb6SAlexander V. Chernikov SLIST_FOREACH_SAFE(ent, &old_head[i], next, ent_next) { 3150914bffb6SAlexander V. Chernikov nhash = hash_flow_ent(ent, mi->size); 3151914bffb6SAlexander V. Chernikov SLIST_INSERT_HEAD(&new_head[nhash], ent, next); 3152914bffb6SAlexander V. Chernikov } 3153914bffb6SAlexander V. Chernikov } 3154914bffb6SAlexander V. Chernikov 3155914bffb6SAlexander V. Chernikov ti->state = new_head; 3156914bffb6SAlexander V. Chernikov ti->data = mi->size; 3157914bffb6SAlexander V. Chernikov cfg->head = new_head; 3158914bffb6SAlexander V. Chernikov cfg->size = mi->size; 3159914bffb6SAlexander V. Chernikov 3160914bffb6SAlexander V. Chernikov mi->main_ptr = old_head; 3161914bffb6SAlexander V. Chernikov 3162914bffb6SAlexander V. Chernikov return (0); 3163914bffb6SAlexander V. Chernikov } 3164914bffb6SAlexander V. Chernikov 3165914bffb6SAlexander V. Chernikov /* 3166914bffb6SAlexander V. Chernikov * Free unneded array. 3167914bffb6SAlexander V. Chernikov */ 3168914bffb6SAlexander V. Chernikov static void 3169914bffb6SAlexander V. Chernikov ta_flush_mod_fhash(void *ta_buf) 3170914bffb6SAlexander V. Chernikov { 3171914bffb6SAlexander V. Chernikov struct mod_item *mi; 3172914bffb6SAlexander V. Chernikov 3173914bffb6SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 3174914bffb6SAlexander V. Chernikov if (mi->main_ptr != NULL) 3175914bffb6SAlexander V. Chernikov free(mi->main_ptr, M_IPFW); 3176914bffb6SAlexander V. Chernikov } 3177914bffb6SAlexander V. Chernikov 3178914bffb6SAlexander V. Chernikov struct table_algo flow_hash = { 3179914bffb6SAlexander V. Chernikov .name = "flow:hash", 3180914bffb6SAlexander V. Chernikov .type = IPFW_TABLE_FLOW, 318157a1cf95SAlexander V. Chernikov .flags = TA_FLAG_DEFAULT, 318257a1cf95SAlexander V. Chernikov .ta_buf_size = sizeof(struct ta_buf_fhash), 3183914bffb6SAlexander V. Chernikov .init = ta_init_fhash, 3184914bffb6SAlexander V. Chernikov .destroy = ta_destroy_fhash, 3185914bffb6SAlexander V. Chernikov .prepare_add = ta_prepare_add_fhash, 3186914bffb6SAlexander V. Chernikov .prepare_del = ta_prepare_del_fhash, 3187914bffb6SAlexander V. Chernikov .add = ta_add_fhash, 3188914bffb6SAlexander V. Chernikov .del = ta_del_fhash, 3189914bffb6SAlexander V. Chernikov .flush_entry = ta_flush_fhash_entry, 3190914bffb6SAlexander V. Chernikov .foreach = ta_foreach_fhash, 3191914bffb6SAlexander V. Chernikov .dump_tentry = ta_dump_fhash_tentry, 3192914bffb6SAlexander V. Chernikov .find_tentry = ta_find_fhash_tentry, 3193b6ee846eSAlexander V. Chernikov .has_space = ta_has_space_fhash, 3194914bffb6SAlexander V. Chernikov .prepare_mod = ta_prepare_mod_fhash, 3195914bffb6SAlexander V. Chernikov .fill_mod = ta_fill_mod_fhash, 3196914bffb6SAlexander V. Chernikov .modify = ta_modify_fhash, 3197914bffb6SAlexander V. Chernikov .flush_mod = ta_flush_mod_fhash, 3198914bffb6SAlexander V. Chernikov }; 31993fe2ef91SAlexander V. Chernikov 32009f7d47b0SAlexander V. Chernikov void 32010b565ac0SAlexander V. Chernikov ipfw_table_algo_init(struct ip_fw_chain *ch) 32029f7d47b0SAlexander V. Chernikov { 32030b565ac0SAlexander V. Chernikov size_t sz; 32040b565ac0SAlexander V. Chernikov 32059f7d47b0SAlexander V. Chernikov /* 32069f7d47b0SAlexander V. Chernikov * Register all algorithms presented here. 32079f7d47b0SAlexander V. Chernikov */ 32080b565ac0SAlexander V. Chernikov sz = sizeof(struct table_algo); 32090b565ac0SAlexander V. Chernikov ipfw_add_table_algo(ch, &cidr_radix, sz, &cidr_radix.idx); 32100b565ac0SAlexander V. Chernikov ipfw_add_table_algo(ch, &cidr_hash, sz, &cidr_hash.idx); 32110b565ac0SAlexander V. Chernikov ipfw_add_table_algo(ch, &iface_idx, sz, &iface_idx.idx); 3212b23d5de9SAlexander V. Chernikov ipfw_add_table_algo(ch, &number_array, sz, &number_array.idx); 3213914bffb6SAlexander V. Chernikov ipfw_add_table_algo(ch, &flow_hash, sz, &flow_hash.idx); 32149f7d47b0SAlexander V. Chernikov } 32159f7d47b0SAlexander V. Chernikov 32169f7d47b0SAlexander V. Chernikov void 32170b565ac0SAlexander V. Chernikov ipfw_table_algo_destroy(struct ip_fw_chain *ch) 32189f7d47b0SAlexander V. Chernikov { 32190b565ac0SAlexander V. Chernikov 32200b565ac0SAlexander V. Chernikov ipfw_del_table_algo(ch, cidr_radix.idx); 32210b565ac0SAlexander V. Chernikov ipfw_del_table_algo(ch, cidr_hash.idx); 32220b565ac0SAlexander V. Chernikov ipfw_del_table_algo(ch, iface_idx.idx); 3223b23d5de9SAlexander V. Chernikov ipfw_del_table_algo(ch, number_array.idx); 3224914bffb6SAlexander V. Chernikov ipfw_del_table_algo(ch, flow_hash.idx); 32259f7d47b0SAlexander V. Chernikov } 32269f7d47b0SAlexander V. Chernikov 32279f7d47b0SAlexander V. Chernikov 3228