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 #include <net/route.h> 529f7d47b0SAlexander V. Chernikov #include <net/vnet.h> 539f7d47b0SAlexander V. Chernikov 549f7d47b0SAlexander V. Chernikov #include <netinet/in.h> 559f7d47b0SAlexander V. Chernikov #include <netinet/ip_var.h> /* struct ipfw_rule_ref */ 569f7d47b0SAlexander V. Chernikov #include <netinet/ip_fw.h> 579f7d47b0SAlexander V. Chernikov 589f7d47b0SAlexander V. Chernikov #include <netpfil/ipfw/ip_fw_private.h> 59ea761a5dSAlexander V. Chernikov #include <netpfil/ipfw/ip_fw_table.h> 609f7d47b0SAlexander V. Chernikov 619f7d47b0SAlexander V. Chernikov static MALLOC_DEFINE(M_IPFW_TBL, "ipfw_tbl", "IpFw tables"); 629f7d47b0SAlexander V. Chernikov 6368394ec8SAlexander V. Chernikov static int badd(const void *key, void *item, void *base, size_t nmemb, 6468394ec8SAlexander V. Chernikov size_t size, int (*compar) (const void *, const void *)); 6568394ec8SAlexander V. Chernikov static int bdel(const void *key, void *base, size_t nmemb, size_t size, 6668394ec8SAlexander V. Chernikov int (*compar) (const void *, const void *)); 6768394ec8SAlexander V. Chernikov 6868394ec8SAlexander V. Chernikov 6968394ec8SAlexander V. Chernikov /* 7068394ec8SAlexander V. Chernikov * CIDR implementation using radix 7168394ec8SAlexander V. Chernikov * 7268394ec8SAlexander V. Chernikov */ 7368394ec8SAlexander V. Chernikov 749f7d47b0SAlexander V. Chernikov /* 759f7d47b0SAlexander V. Chernikov * The radix code expects addr and mask to be array of bytes, 769f7d47b0SAlexander V. Chernikov * with the first byte being the length of the array. rn_inithead 779f7d47b0SAlexander V. Chernikov * is called with the offset in bits of the lookup key within the 789f7d47b0SAlexander V. Chernikov * array. If we use a sockaddr_in as the underlying type, 799f7d47b0SAlexander V. Chernikov * sin_len is conveniently located at offset 0, sin_addr is at 809f7d47b0SAlexander V. Chernikov * offset 4 and normally aligned. 819f7d47b0SAlexander V. Chernikov * But for portability, let's avoid assumption and make the code explicit 829f7d47b0SAlexander V. Chernikov */ 839f7d47b0SAlexander V. Chernikov #define KEY_LEN(v) *((uint8_t *)&(v)) 849f7d47b0SAlexander V. Chernikov /* 859f7d47b0SAlexander V. Chernikov * Do not require radix to compare more than actual IPv4/IPv6 address 869f7d47b0SAlexander V. Chernikov */ 879f7d47b0SAlexander V. Chernikov #define KEY_LEN_INET (offsetof(struct sockaddr_in, sin_addr) + sizeof(in_addr_t)) 88e0a8b9eeSAlexander V. Chernikov #define KEY_LEN_INET6 (offsetof(struct sa_in6, sin6_addr) + sizeof(struct in6_addr)) 899f7d47b0SAlexander V. Chernikov 909f7d47b0SAlexander V. Chernikov #define OFF_LEN_INET (8 * offsetof(struct sockaddr_in, sin_addr)) 91e0a8b9eeSAlexander V. Chernikov #define OFF_LEN_INET6 (8 * offsetof(struct sa_in6, sin6_addr)) 929f7d47b0SAlexander V. Chernikov 93e0a8b9eeSAlexander V. Chernikov struct radix_cidr_entry { 949f7d47b0SAlexander V. Chernikov struct radix_node rn[2]; 95e0a8b9eeSAlexander V. Chernikov struct sockaddr_in addr; 96e0a8b9eeSAlexander V. Chernikov uint32_t value; 97e0a8b9eeSAlexander V. Chernikov uint8_t masklen; 98e0a8b9eeSAlexander V. Chernikov }; 99e0a8b9eeSAlexander V. Chernikov 100e0a8b9eeSAlexander V. Chernikov struct sa_in6 { 101e0a8b9eeSAlexander V. Chernikov uint8_t sin6_len; 102e0a8b9eeSAlexander V. Chernikov uint8_t sin6_family; 103e0a8b9eeSAlexander V. Chernikov uint8_t pad[2]; 104e0a8b9eeSAlexander V. Chernikov struct in6_addr sin6_addr; 105e0a8b9eeSAlexander V. Chernikov }; 106e0a8b9eeSAlexander V. Chernikov 107e0a8b9eeSAlexander V. Chernikov struct radix_cidr_xentry { 108e0a8b9eeSAlexander V. Chernikov struct radix_node rn[2]; 109e0a8b9eeSAlexander V. Chernikov struct sa_in6 addr6; 110e0a8b9eeSAlexander V. Chernikov uint32_t value; 111e0a8b9eeSAlexander V. Chernikov uint8_t masklen; 1129f7d47b0SAlexander V. Chernikov }; 1139f7d47b0SAlexander V. Chernikov 1149f7d47b0SAlexander V. Chernikov static int 1159f7d47b0SAlexander V. Chernikov ta_lookup_radix(struct table_info *ti, void *key, uint32_t keylen, 1169f7d47b0SAlexander V. Chernikov uint32_t *val) 1179f7d47b0SAlexander V. Chernikov { 1189f7d47b0SAlexander V. Chernikov struct radix_node_head *rnh; 1199f7d47b0SAlexander V. Chernikov 1209f7d47b0SAlexander V. Chernikov if (keylen == sizeof(in_addr_t)) { 121e0a8b9eeSAlexander V. Chernikov struct radix_cidr_entry *ent; 1229f7d47b0SAlexander V. Chernikov struct sockaddr_in sa; 1239f7d47b0SAlexander V. Chernikov KEY_LEN(sa) = KEY_LEN_INET; 1249f7d47b0SAlexander V. Chernikov sa.sin_addr.s_addr = *((in_addr_t *)key); 1259f7d47b0SAlexander V. Chernikov rnh = (struct radix_node_head *)ti->state; 126e0a8b9eeSAlexander V. Chernikov ent = (struct radix_cidr_entry *)(rnh->rnh_matchaddr(&sa, rnh)); 1279f7d47b0SAlexander V. Chernikov if (ent != NULL) { 1289f7d47b0SAlexander V. Chernikov *val = ent->value; 1299f7d47b0SAlexander V. Chernikov return (1); 1309f7d47b0SAlexander V. Chernikov } 1319f7d47b0SAlexander V. Chernikov } else { 132e0a8b9eeSAlexander V. Chernikov struct radix_cidr_xentry *xent; 133e0a8b9eeSAlexander V. Chernikov struct sa_in6 sa6; 1349f7d47b0SAlexander V. Chernikov KEY_LEN(sa6) = KEY_LEN_INET6; 1359f7d47b0SAlexander V. Chernikov memcpy(&sa6.sin6_addr, key, sizeof(struct in6_addr)); 1369f7d47b0SAlexander V. Chernikov rnh = (struct radix_node_head *)ti->xstate; 137e0a8b9eeSAlexander V. Chernikov xent = (struct radix_cidr_xentry *)(rnh->rnh_matchaddr(&sa6, rnh)); 1389f7d47b0SAlexander V. Chernikov if (xent != NULL) { 1399f7d47b0SAlexander V. Chernikov *val = xent->value; 1409f7d47b0SAlexander V. Chernikov return (1); 1419f7d47b0SAlexander V. Chernikov } 1429f7d47b0SAlexander V. Chernikov } 1439f7d47b0SAlexander V. Chernikov 1449f7d47b0SAlexander V. Chernikov return (0); 1459f7d47b0SAlexander V. Chernikov } 1469f7d47b0SAlexander V. Chernikov 1479f7d47b0SAlexander V. Chernikov /* 1489f7d47b0SAlexander V. Chernikov * New table 1499f7d47b0SAlexander V. Chernikov */ 1509f7d47b0SAlexander V. Chernikov static int 15168394ec8SAlexander V. Chernikov ta_init_radix(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti, 152914bffb6SAlexander V. Chernikov char *data, uint8_t tflags) 1539f7d47b0SAlexander V. Chernikov { 1549f7d47b0SAlexander V. Chernikov 1559f7d47b0SAlexander V. Chernikov if (!rn_inithead(&ti->state, OFF_LEN_INET)) 1569f7d47b0SAlexander V. Chernikov return (ENOMEM); 1579f7d47b0SAlexander V. Chernikov if (!rn_inithead(&ti->xstate, OFF_LEN_INET6)) { 1589f7d47b0SAlexander V. Chernikov rn_detachhead(&ti->state); 1599f7d47b0SAlexander V. Chernikov return (ENOMEM); 1609f7d47b0SAlexander V. Chernikov } 1619f7d47b0SAlexander V. Chernikov 1629f7d47b0SAlexander V. Chernikov *ta_state = NULL; 1639f7d47b0SAlexander V. Chernikov ti->lookup = ta_lookup_radix; 1649f7d47b0SAlexander V. Chernikov 1659f7d47b0SAlexander V. Chernikov return (0); 1669f7d47b0SAlexander V. Chernikov } 1679f7d47b0SAlexander V. Chernikov 1689f7d47b0SAlexander V. Chernikov static int 1699f7d47b0SAlexander V. Chernikov flush_table_entry(struct radix_node *rn, void *arg) 1709f7d47b0SAlexander V. Chernikov { 1719f7d47b0SAlexander V. Chernikov struct radix_node_head * const rnh = arg; 172e0a8b9eeSAlexander V. Chernikov struct radix_cidr_entry *ent; 1739f7d47b0SAlexander V. Chernikov 174e0a8b9eeSAlexander V. Chernikov ent = (struct radix_cidr_entry *) 1759f7d47b0SAlexander V. Chernikov rnh->rnh_deladdr(rn->rn_key, rn->rn_mask, rnh); 1769f7d47b0SAlexander V. Chernikov if (ent != NULL) 1779f7d47b0SAlexander V. Chernikov free(ent, M_IPFW_TBL); 1789f7d47b0SAlexander V. Chernikov return (0); 1799f7d47b0SAlexander V. Chernikov } 1809f7d47b0SAlexander V. Chernikov 1819f7d47b0SAlexander V. Chernikov static void 1829f7d47b0SAlexander V. Chernikov ta_destroy_radix(void *ta_state, struct table_info *ti) 1839f7d47b0SAlexander V. Chernikov { 1849f7d47b0SAlexander V. Chernikov struct radix_node_head *rnh; 1859f7d47b0SAlexander V. Chernikov 1869f7d47b0SAlexander V. Chernikov rnh = (struct radix_node_head *)(ti->state); 1879f7d47b0SAlexander V. Chernikov rnh->rnh_walktree(rnh, flush_table_entry, rnh); 1889f7d47b0SAlexander V. Chernikov rn_detachhead(&ti->state); 1899f7d47b0SAlexander V. Chernikov 1909f7d47b0SAlexander V. Chernikov rnh = (struct radix_node_head *)(ti->xstate); 1919f7d47b0SAlexander V. Chernikov rnh->rnh_walktree(rnh, flush_table_entry, rnh); 1929f7d47b0SAlexander V. Chernikov rn_detachhead(&ti->xstate); 1939f7d47b0SAlexander V. Chernikov } 1949f7d47b0SAlexander V. Chernikov 1959f7d47b0SAlexander V. Chernikov static int 19681d3153dSAlexander V. Chernikov ta_dump_radix_tentry(void *ta_state, struct table_info *ti, void *e, 19781d3153dSAlexander V. Chernikov ipfw_obj_tentry *tent) 1989f7d47b0SAlexander V. Chernikov { 199e0a8b9eeSAlexander V. Chernikov struct radix_cidr_entry *n; 200e0a8b9eeSAlexander V. Chernikov struct radix_cidr_xentry *xn; 2019f7d47b0SAlexander V. Chernikov 202e0a8b9eeSAlexander V. Chernikov n = (struct radix_cidr_entry *)e; 2039f7d47b0SAlexander V. Chernikov 2049f7d47b0SAlexander V. Chernikov /* Guess IPv4/IPv6 radix by sockaddr family */ 2059f7d47b0SAlexander V. Chernikov if (n->addr.sin_family == AF_INET) { 20681d3153dSAlexander V. Chernikov tent->k.addr.s_addr = n->addr.sin_addr.s_addr; 207e0a8b9eeSAlexander V. Chernikov tent->masklen = n->masklen; 20881d3153dSAlexander V. Chernikov tent->subtype = AF_INET; 20981d3153dSAlexander V. Chernikov tent->value = n->value; 2109f7d47b0SAlexander V. Chernikov #ifdef INET6 2119f7d47b0SAlexander V. Chernikov } else { 212e0a8b9eeSAlexander V. Chernikov xn = (struct radix_cidr_xentry *)e; 213e0a8b9eeSAlexander V. Chernikov memcpy(&tent->k, &xn->addr6.sin6_addr, sizeof(struct in6_addr)); 214e0a8b9eeSAlexander V. Chernikov tent->masklen = xn->masklen; 21581d3153dSAlexander V. Chernikov tent->subtype = AF_INET6; 21681d3153dSAlexander V. Chernikov tent->value = xn->value; 2179f7d47b0SAlexander V. Chernikov #endif 2189f7d47b0SAlexander V. Chernikov } 2199f7d47b0SAlexander V. Chernikov 2209f7d47b0SAlexander V. Chernikov return (0); 2219f7d47b0SAlexander V. Chernikov } 2229f7d47b0SAlexander V. Chernikov 22381d3153dSAlexander V. Chernikov static int 224914bffb6SAlexander V. Chernikov ta_find_radix_tentry(void *ta_state, struct table_info *ti, 225914bffb6SAlexander V. Chernikov ipfw_obj_tentry *tent) 22681d3153dSAlexander V. Chernikov { 22781d3153dSAlexander V. Chernikov struct radix_node_head *rnh; 22881d3153dSAlexander V. Chernikov void *e; 22981d3153dSAlexander V. Chernikov 23081d3153dSAlexander V. Chernikov e = NULL; 231914bffb6SAlexander V. Chernikov if (tent->subtype == AF_INET) { 23281d3153dSAlexander V. Chernikov struct sockaddr_in sa; 23381d3153dSAlexander V. Chernikov KEY_LEN(sa) = KEY_LEN_INET; 234914bffb6SAlexander V. Chernikov sa.sin_addr.s_addr = tent->k.addr.s_addr; 23581d3153dSAlexander V. Chernikov rnh = (struct radix_node_head *)ti->state; 23681d3153dSAlexander V. Chernikov e = rnh->rnh_matchaddr(&sa, rnh); 23781d3153dSAlexander V. Chernikov } else { 238e0a8b9eeSAlexander V. Chernikov struct sa_in6 sa6; 23981d3153dSAlexander V. Chernikov KEY_LEN(sa6) = KEY_LEN_INET6; 240914bffb6SAlexander V. Chernikov memcpy(&sa6.sin6_addr, &tent->k.addr6, sizeof(struct in6_addr)); 24181d3153dSAlexander V. Chernikov rnh = (struct radix_node_head *)ti->xstate; 24281d3153dSAlexander V. Chernikov e = rnh->rnh_matchaddr(&sa6, rnh); 24381d3153dSAlexander V. Chernikov } 24481d3153dSAlexander V. Chernikov 24581d3153dSAlexander V. Chernikov if (e != NULL) { 24681d3153dSAlexander V. Chernikov ta_dump_radix_tentry(ta_state, ti, e, tent); 24781d3153dSAlexander V. Chernikov return (0); 24881d3153dSAlexander V. Chernikov } 24981d3153dSAlexander V. Chernikov 25081d3153dSAlexander V. Chernikov return (ENOENT); 25181d3153dSAlexander V. Chernikov } 25281d3153dSAlexander V. Chernikov 2539f7d47b0SAlexander V. Chernikov static void 2549f7d47b0SAlexander V. Chernikov ta_foreach_radix(void *ta_state, struct table_info *ti, ta_foreach_f *f, 2559f7d47b0SAlexander V. Chernikov void *arg) 2569f7d47b0SAlexander V. Chernikov { 2579f7d47b0SAlexander V. Chernikov struct radix_node_head *rnh; 2589f7d47b0SAlexander V. Chernikov 2599f7d47b0SAlexander V. Chernikov rnh = (struct radix_node_head *)(ti->state); 2609f7d47b0SAlexander V. Chernikov rnh->rnh_walktree(rnh, (walktree_f_t *)f, arg); 2619f7d47b0SAlexander V. Chernikov 2629f7d47b0SAlexander V. Chernikov rnh = (struct radix_node_head *)(ti->xstate); 2639f7d47b0SAlexander V. Chernikov rnh->rnh_walktree(rnh, (walktree_f_t *)f, arg); 2649f7d47b0SAlexander V. Chernikov } 2659f7d47b0SAlexander V. Chernikov 2669f7d47b0SAlexander V. Chernikov 2679f7d47b0SAlexander V. Chernikov struct ta_buf_cidr 2689f7d47b0SAlexander V. Chernikov { 2699f7d47b0SAlexander V. Chernikov struct sockaddr *addr_ptr; 2709f7d47b0SAlexander V. Chernikov struct sockaddr *mask_ptr; 2719f7d47b0SAlexander V. Chernikov void *ent_ptr; 2729f7d47b0SAlexander V. Chernikov union { 2739f7d47b0SAlexander V. Chernikov struct { 2749f7d47b0SAlexander V. Chernikov struct sockaddr_in sa; 2759f7d47b0SAlexander V. Chernikov struct sockaddr_in ma; 2769f7d47b0SAlexander V. Chernikov } a4; 2779f7d47b0SAlexander V. Chernikov struct { 278e0a8b9eeSAlexander V. Chernikov struct sa_in6 sa; 279e0a8b9eeSAlexander V. Chernikov struct sa_in6 ma; 2809f7d47b0SAlexander V. Chernikov } a6; 2819f7d47b0SAlexander V. Chernikov } addr; 2829f7d47b0SAlexander V. Chernikov }; 2839f7d47b0SAlexander V. Chernikov 2849f7d47b0SAlexander V. Chernikov #ifdef INET6 2859f7d47b0SAlexander V. Chernikov static inline void 2869f7d47b0SAlexander V. Chernikov ipv6_writemask(struct in6_addr *addr6, uint8_t mask) 2879f7d47b0SAlexander V. Chernikov { 2889f7d47b0SAlexander V. Chernikov uint32_t *cp; 2899f7d47b0SAlexander V. Chernikov 2909f7d47b0SAlexander V. Chernikov for (cp = (uint32_t *)addr6; mask >= 32; mask -= 32) 2919f7d47b0SAlexander V. Chernikov *cp++ = 0xFFFFFFFF; 2929f7d47b0SAlexander V. Chernikov *cp = htonl(mask ? ~((1 << (32 - mask)) - 1) : 0); 2939f7d47b0SAlexander V. Chernikov } 2949f7d47b0SAlexander V. Chernikov #endif 2959f7d47b0SAlexander V. Chernikov 296*2e324d29SAlexander V. Chernikov static void 297*2e324d29SAlexander V. Chernikov tei_to_sockaddr_ent(struct tentry_info *tei, struct sockaddr *sa, 298*2e324d29SAlexander V. Chernikov struct sockaddr *ma, int *set_mask) 299*2e324d29SAlexander V. Chernikov { 300*2e324d29SAlexander V. Chernikov int mlen; 301*2e324d29SAlexander V. Chernikov struct sockaddr_in *addr, *mask; 302*2e324d29SAlexander V. Chernikov struct sockaddr_in6 *addr6, *mask6; 303*2e324d29SAlexander V. Chernikov in_addr_t a4; 304*2e324d29SAlexander V. Chernikov 305*2e324d29SAlexander V. Chernikov mlen = tei->masklen; 306*2e324d29SAlexander V. Chernikov 307*2e324d29SAlexander V. Chernikov if (tei->subtype == AF_INET) { 308*2e324d29SAlexander V. Chernikov #ifdef INET 309*2e324d29SAlexander V. Chernikov addr = (struct sockaddr_in *)sa; 310*2e324d29SAlexander V. Chernikov mask = (struct sockaddr_in *)ma; 311*2e324d29SAlexander V. Chernikov /* Set 'total' structure length */ 312*2e324d29SAlexander V. Chernikov KEY_LEN(*addr) = KEY_LEN_INET; 313*2e324d29SAlexander V. Chernikov KEY_LEN(*mask) = KEY_LEN_INET; 314*2e324d29SAlexander V. Chernikov addr->sin_family = AF_INET; 315*2e324d29SAlexander V. Chernikov mask->sin_addr.s_addr = 316*2e324d29SAlexander V. Chernikov htonl(mlen ? ~((1 << (32 - mlen)) - 1) : 0); 317*2e324d29SAlexander V. Chernikov a4 = *((in_addr_t *)tei->paddr); 318*2e324d29SAlexander V. Chernikov addr->sin_addr.s_addr = a4 & mask->sin_addr.s_addr; 319*2e324d29SAlexander V. Chernikov if (mlen != 32) 320*2e324d29SAlexander V. Chernikov *set_mask = 1; 321*2e324d29SAlexander V. Chernikov else 322*2e324d29SAlexander V. Chernikov *set_mask = 0; 323*2e324d29SAlexander V. Chernikov #endif 324*2e324d29SAlexander V. Chernikov #ifdef INET6 325*2e324d29SAlexander V. Chernikov } else if (tei->subtype == AF_INET6) { 326*2e324d29SAlexander V. Chernikov /* IPv6 case */ 327*2e324d29SAlexander V. Chernikov addr6 = (struct sockaddr_in6 *)sa; 328*2e324d29SAlexander V. Chernikov mask6 = (struct sockaddr_in6 *)ma; 329*2e324d29SAlexander V. Chernikov /* Set 'total' structure length */ 330*2e324d29SAlexander V. Chernikov KEY_LEN(*addr6) = KEY_LEN_INET6; 331*2e324d29SAlexander V. Chernikov KEY_LEN(*mask6) = KEY_LEN_INET6; 332*2e324d29SAlexander V. Chernikov addr6->sin6_family = AF_INET6; 333*2e324d29SAlexander V. Chernikov ipv6_writemask(&mask6->sin6_addr, mlen); 334*2e324d29SAlexander V. Chernikov memcpy(&addr6->sin6_addr, tei->paddr, sizeof(struct in6_addr)); 335*2e324d29SAlexander V. Chernikov APPLY_MASK(&addr6->sin6_addr, &mask6->sin6_addr); 336*2e324d29SAlexander V. Chernikov if (mlen != 128) 337*2e324d29SAlexander V. Chernikov *set_mask = 1; 338*2e324d29SAlexander V. Chernikov else 339*2e324d29SAlexander V. Chernikov *set_mask = 0; 340*2e324d29SAlexander V. Chernikov } 341*2e324d29SAlexander V. Chernikov #endif 342*2e324d29SAlexander V. Chernikov } 3439f7d47b0SAlexander V. Chernikov 3449f7d47b0SAlexander V. Chernikov static int 34568394ec8SAlexander V. Chernikov ta_prepare_add_cidr(struct ip_fw_chain *ch, struct tentry_info *tei, 34668394ec8SAlexander V. Chernikov void *ta_buf) 3479f7d47b0SAlexander V. Chernikov { 3489f7d47b0SAlexander V. Chernikov struct ta_buf_cidr *tb; 349e0a8b9eeSAlexander V. Chernikov struct radix_cidr_entry *ent; 350e0a8b9eeSAlexander V. Chernikov struct radix_cidr_xentry *xent; 351*2e324d29SAlexander V. Chernikov struct sockaddr *addr, *mask; 352*2e324d29SAlexander V. Chernikov int mlen, set_mask; 3539f7d47b0SAlexander V. Chernikov 3549f7d47b0SAlexander V. Chernikov tb = (struct ta_buf_cidr *)ta_buf; 3559f7d47b0SAlexander V. Chernikov memset(tb, 0, sizeof(struct ta_buf_cidr)); 3569f7d47b0SAlexander V. Chernikov 3579f7d47b0SAlexander V. Chernikov mlen = tei->masklen; 358*2e324d29SAlexander V. Chernikov set_mask = 0; 3599f7d47b0SAlexander V. Chernikov 360ac35ff17SAlexander V. Chernikov if (tei->subtype == AF_INET) { 3619f7d47b0SAlexander V. Chernikov #ifdef INET 3629f7d47b0SAlexander V. Chernikov if (mlen > 32) 3639f7d47b0SAlexander V. Chernikov return (EINVAL); 3649f7d47b0SAlexander V. Chernikov ent = malloc(sizeof(*ent), M_IPFW_TBL, M_WAITOK | M_ZERO); 3659f7d47b0SAlexander V. Chernikov ent->value = tei->value; 366e0a8b9eeSAlexander V. Chernikov ent->masklen = mlen; 367*2e324d29SAlexander V. Chernikov 368*2e324d29SAlexander V. Chernikov addr = (struct sockaddr *)&ent->addr; 369*2e324d29SAlexander V. Chernikov mask = (struct sockaddr *)&tb->addr.a4.ma; 3709f7d47b0SAlexander V. Chernikov tb->ent_ptr = ent; 3719f7d47b0SAlexander V. Chernikov #endif 3729f7d47b0SAlexander V. Chernikov #ifdef INET6 373ac35ff17SAlexander V. Chernikov } else if (tei->subtype == AF_INET6) { 3749f7d47b0SAlexander V. Chernikov /* IPv6 case */ 3759f7d47b0SAlexander V. Chernikov if (mlen > 128) 3769f7d47b0SAlexander V. Chernikov return (EINVAL); 3779f7d47b0SAlexander V. Chernikov xent = malloc(sizeof(*xent), M_IPFW_TBL, M_WAITOK | M_ZERO); 3789f7d47b0SAlexander V. Chernikov xent->value = tei->value; 379e0a8b9eeSAlexander V. Chernikov xent->masklen = mlen; 380*2e324d29SAlexander V. Chernikov 381*2e324d29SAlexander V. Chernikov addr = (struct sockaddr *)&xent->addr6; 382*2e324d29SAlexander V. Chernikov mask = (struct sockaddr *)&tb->addr.a6.ma; 3839f7d47b0SAlexander V. Chernikov tb->ent_ptr = xent; 3849f7d47b0SAlexander V. Chernikov #endif 3859f7d47b0SAlexander V. Chernikov } else { 3869f7d47b0SAlexander V. Chernikov /* Unknown CIDR type */ 3879f7d47b0SAlexander V. Chernikov return (EINVAL); 3889f7d47b0SAlexander V. Chernikov } 3899f7d47b0SAlexander V. Chernikov 390*2e324d29SAlexander V. Chernikov tei_to_sockaddr_ent(tei, addr, mask, &set_mask); 391*2e324d29SAlexander V. Chernikov /* Set pointers */ 392*2e324d29SAlexander V. Chernikov tb->addr_ptr = addr; 393*2e324d29SAlexander V. Chernikov if (set_mask != 0) 394*2e324d29SAlexander V. Chernikov tb->mask_ptr = mask; 395*2e324d29SAlexander V. Chernikov 3969f7d47b0SAlexander V. Chernikov return (0); 3979f7d47b0SAlexander V. Chernikov } 3989f7d47b0SAlexander V. Chernikov 3999f7d47b0SAlexander V. Chernikov static int 400adea6201SAlexander V. Chernikov ta_add_cidr(void *ta_state, struct table_info *ti, struct tentry_info *tei, 401adea6201SAlexander V. Chernikov void *ta_buf, uint64_t *pflags, uint32_t *pnum) 4029f7d47b0SAlexander V. Chernikov { 4039f7d47b0SAlexander V. Chernikov struct radix_node_head *rnh; 4049f7d47b0SAlexander V. Chernikov struct radix_node *rn; 4059f7d47b0SAlexander V. Chernikov struct ta_buf_cidr *tb; 406ac35ff17SAlexander V. Chernikov uint32_t value; 4079f7d47b0SAlexander V. Chernikov 4089f7d47b0SAlexander V. Chernikov tb = (struct ta_buf_cidr *)ta_buf; 4099f7d47b0SAlexander V. Chernikov 410ac35ff17SAlexander V. Chernikov if (tei->subtype == AF_INET) 4119f7d47b0SAlexander V. Chernikov rnh = ti->state; 4129f7d47b0SAlexander V. Chernikov else 4139f7d47b0SAlexander V. Chernikov rnh = ti->xstate; 4149f7d47b0SAlexander V. Chernikov 4159f7d47b0SAlexander V. Chernikov rn = rnh->rnh_addaddr(tb->addr_ptr, tb->mask_ptr, rnh, tb->ent_ptr); 4169f7d47b0SAlexander V. Chernikov 417ac35ff17SAlexander V. Chernikov if (rn == NULL) { 418ac35ff17SAlexander V. Chernikov if ((tei->flags & TEI_FLAGS_UPDATE) == 0) 4199f7d47b0SAlexander V. Chernikov return (EEXIST); 420ac35ff17SAlexander V. Chernikov /* Record already exists. Update value if we're asked to */ 421ac35ff17SAlexander V. Chernikov rn = rnh->rnh_lookup(tb->addr_ptr, tb->mask_ptr, rnh); 422ac35ff17SAlexander V. Chernikov if (rn == NULL) { 423ac35ff17SAlexander V. Chernikov 424ac35ff17SAlexander V. Chernikov /* 425ac35ff17SAlexander V. Chernikov * Radix may have failed addition for other reasons 426ac35ff17SAlexander V. Chernikov * like failure in mask allocation code. 427ac35ff17SAlexander V. Chernikov */ 428ac35ff17SAlexander V. Chernikov return (EINVAL); 429ac35ff17SAlexander V. Chernikov } 430ac35ff17SAlexander V. Chernikov 431ac35ff17SAlexander V. Chernikov if (tei->subtype == AF_INET) { 432ac35ff17SAlexander V. Chernikov /* IPv4. */ 433e0a8b9eeSAlexander V. Chernikov value = ((struct radix_cidr_entry *)tb->ent_ptr)->value; 434e0a8b9eeSAlexander V. Chernikov ((struct radix_cidr_entry *)rn)->value = value; 435ac35ff17SAlexander V. Chernikov } else { 436ac35ff17SAlexander V. Chernikov /* IPv6 */ 437e0a8b9eeSAlexander V. Chernikov value = ((struct radix_cidr_xentry *)tb->ent_ptr)->value; 438e0a8b9eeSAlexander V. Chernikov ((struct radix_cidr_xentry *)rn)->value = value; 439ac35ff17SAlexander V. Chernikov } 440ac35ff17SAlexander V. Chernikov 441ac35ff17SAlexander V. Chernikov /* Indicate that update has happened instead of addition */ 442ac35ff17SAlexander V. Chernikov tei->flags |= TEI_FLAGS_UPDATED; 443adea6201SAlexander V. Chernikov *pnum = 0; 444e0a8b9eeSAlexander V. Chernikov 445e0a8b9eeSAlexander V. Chernikov return (0); 446ac35ff17SAlexander V. Chernikov } 447ac35ff17SAlexander V. Chernikov 448ac35ff17SAlexander V. Chernikov tb->ent_ptr = NULL; 449adea6201SAlexander V. Chernikov *pnum = 1; 4509f7d47b0SAlexander V. Chernikov 4519f7d47b0SAlexander V. Chernikov return (0); 4529f7d47b0SAlexander V. Chernikov } 4539f7d47b0SAlexander V. Chernikov 4549f7d47b0SAlexander V. Chernikov static int 45568394ec8SAlexander V. Chernikov ta_prepare_del_cidr(struct ip_fw_chain *ch, struct tentry_info *tei, 45668394ec8SAlexander V. Chernikov void *ta_buf) 4579f7d47b0SAlexander V. Chernikov { 4589f7d47b0SAlexander V. Chernikov struct ta_buf_cidr *tb; 459*2e324d29SAlexander V. Chernikov struct sockaddr *addr, *mask; 460*2e324d29SAlexander V. Chernikov int mlen, set_mask; 4619f7d47b0SAlexander V. Chernikov 4629f7d47b0SAlexander V. Chernikov tb = (struct ta_buf_cidr *)ta_buf; 4639f7d47b0SAlexander V. Chernikov memset(tb, 0, sizeof(struct ta_buf_cidr)); 4649f7d47b0SAlexander V. Chernikov 4659f7d47b0SAlexander V. Chernikov mlen = tei->masklen; 466*2e324d29SAlexander V. Chernikov set_mask = 0; 4679f7d47b0SAlexander V. Chernikov 468ac35ff17SAlexander V. Chernikov if (tei->subtype == AF_INET) { 469e0a8b9eeSAlexander V. Chernikov if (mlen > 32) 470e0a8b9eeSAlexander V. Chernikov return (EINVAL); 471*2e324d29SAlexander V. Chernikov 472*2e324d29SAlexander V. Chernikov addr = (struct sockaddr *)&tb->addr.a4.sa; 473*2e324d29SAlexander V. Chernikov mask = (struct sockaddr *)&tb->addr.a4.ma; 4749f7d47b0SAlexander V. Chernikov #ifdef INET6 475ac35ff17SAlexander V. Chernikov } else if (tei->subtype == AF_INET6) { 4769f7d47b0SAlexander V. Chernikov if (mlen > 128) 4779f7d47b0SAlexander V. Chernikov return (EINVAL); 478*2e324d29SAlexander V. Chernikov 479*2e324d29SAlexander V. Chernikov addr = (struct sockaddr *)&tb->addr.a6.sa; 480*2e324d29SAlexander V. Chernikov mask = (struct sockaddr *)&tb->addr.a6.ma; 4819f7d47b0SAlexander V. Chernikov #endif 4829f7d47b0SAlexander V. Chernikov } else 4839f7d47b0SAlexander V. Chernikov return (EINVAL); 4849f7d47b0SAlexander V. Chernikov 485*2e324d29SAlexander V. Chernikov tei_to_sockaddr_ent(tei, addr, mask, &set_mask); 486*2e324d29SAlexander V. Chernikov tb->addr_ptr = addr; 487*2e324d29SAlexander V. Chernikov if (set_mask != 0) 488*2e324d29SAlexander V. Chernikov tb->mask_ptr = mask; 489*2e324d29SAlexander V. Chernikov 4909f7d47b0SAlexander V. Chernikov return (0); 4919f7d47b0SAlexander V. Chernikov } 4929f7d47b0SAlexander V. Chernikov 4939f7d47b0SAlexander V. Chernikov static int 494adea6201SAlexander V. Chernikov ta_del_cidr(void *ta_state, struct table_info *ti, struct tentry_info *tei, 495adea6201SAlexander V. Chernikov void *ta_buf, uint64_t *pflags, uint32_t *pnum) 4969f7d47b0SAlexander V. Chernikov { 4979f7d47b0SAlexander V. Chernikov struct radix_node_head *rnh; 4989f7d47b0SAlexander V. Chernikov struct radix_node *rn; 4999f7d47b0SAlexander V. Chernikov struct ta_buf_cidr *tb; 5009f7d47b0SAlexander V. Chernikov 5019f7d47b0SAlexander V. Chernikov tb = (struct ta_buf_cidr *)ta_buf; 5029f7d47b0SAlexander V. Chernikov 503ac35ff17SAlexander V. Chernikov if (tei->subtype == AF_INET) 5049f7d47b0SAlexander V. Chernikov rnh = ti->state; 5059f7d47b0SAlexander V. Chernikov else 5069f7d47b0SAlexander V. Chernikov rnh = ti->xstate; 5079f7d47b0SAlexander V. Chernikov 5089f7d47b0SAlexander V. Chernikov rn = rnh->rnh_deladdr(tb->addr_ptr, tb->mask_ptr, rnh); 5099f7d47b0SAlexander V. Chernikov 5109f7d47b0SAlexander V. Chernikov tb->ent_ptr = rn; 5119f7d47b0SAlexander V. Chernikov 5129f7d47b0SAlexander V. Chernikov if (rn == NULL) 51381d3153dSAlexander V. Chernikov return (ENOENT); 5149f7d47b0SAlexander V. Chernikov 515adea6201SAlexander V. Chernikov *pnum = 1; 516adea6201SAlexander V. Chernikov 5179f7d47b0SAlexander V. Chernikov return (0); 5189f7d47b0SAlexander V. Chernikov } 5199f7d47b0SAlexander V. Chernikov 5209f7d47b0SAlexander V. Chernikov static void 52168394ec8SAlexander V. Chernikov ta_flush_cidr_entry(struct ip_fw_chain *ch, struct tentry_info *tei, 52268394ec8SAlexander V. Chernikov void *ta_buf) 5239f7d47b0SAlexander V. Chernikov { 5249f7d47b0SAlexander V. Chernikov struct ta_buf_cidr *tb; 5259f7d47b0SAlexander V. Chernikov 5269f7d47b0SAlexander V. Chernikov tb = (struct ta_buf_cidr *)ta_buf; 5279f7d47b0SAlexander V. Chernikov 528ac35ff17SAlexander V. Chernikov if (tb->ent_ptr != NULL) 5299f7d47b0SAlexander V. Chernikov free(tb->ent_ptr, M_IPFW_TBL); 5309f7d47b0SAlexander V. Chernikov } 5319f7d47b0SAlexander V. Chernikov 53274b941f0SAlexander V. Chernikov struct table_algo cidr_radix = { 533adea6201SAlexander V. Chernikov .name = "cidr:radix", 5349d099b4fSAlexander V. Chernikov .type = IPFW_TABLE_CIDR, 53557a1cf95SAlexander V. Chernikov .flags = TA_FLAG_DEFAULT, 53657a1cf95SAlexander V. Chernikov .ta_buf_size = sizeof(struct ta_buf_cidr), 5379f7d47b0SAlexander V. Chernikov .init = ta_init_radix, 5389f7d47b0SAlexander V. Chernikov .destroy = ta_destroy_radix, 5399f7d47b0SAlexander V. Chernikov .prepare_add = ta_prepare_add_cidr, 5409f7d47b0SAlexander V. Chernikov .prepare_del = ta_prepare_del_cidr, 5419f7d47b0SAlexander V. Chernikov .add = ta_add_cidr, 5429f7d47b0SAlexander V. Chernikov .del = ta_del_cidr, 5439f7d47b0SAlexander V. Chernikov .flush_entry = ta_flush_cidr_entry, 5449f7d47b0SAlexander V. Chernikov .foreach = ta_foreach_radix, 54581d3153dSAlexander V. Chernikov .dump_tentry = ta_dump_radix_tentry, 54681d3153dSAlexander V. Chernikov .find_tentry = ta_find_radix_tentry, 5479f7d47b0SAlexander V. Chernikov }; 5489f7d47b0SAlexander V. Chernikov 5499f7d47b0SAlexander V. Chernikov 5509f7d47b0SAlexander V. Chernikov /* 55174b941f0SAlexander V. Chernikov * cidr:hash cmds 55274b941f0SAlexander V. Chernikov * 55374b941f0SAlexander V. Chernikov * 55474b941f0SAlexander V. Chernikov * ti->data: 55574b941f0SAlexander V. Chernikov * [inv.mask4][inv.mask6][log2hsize4][log2hsize6] 55674b941f0SAlexander V. Chernikov * [ 8][ 8[ 8][ 8] 55774b941f0SAlexander V. Chernikov * 55874b941f0SAlexander V. Chernikov * inv.mask4: 32 - mask 55974b941f0SAlexander V. Chernikov * inv.mask6: 56074b941f0SAlexander V. Chernikov * 1) _slow lookup: mask 56174b941f0SAlexander V. Chernikov * 2) _aligned: (128 - mask) / 8 56274b941f0SAlexander V. Chernikov * 3) _64: 8 563ce2817b5SAlexander V. Chernikov * 564ce2817b5SAlexander V. Chernikov * 565ce2817b5SAlexander V. Chernikov * pflags: 566ce2817b5SAlexander V. Chernikov * [v4=1/v6=0][hsize] 567ce2817b5SAlexander V. Chernikov * [ 32][ 32] 56874b941f0SAlexander V. Chernikov */ 56974b941f0SAlexander V. Chernikov 57074b941f0SAlexander V. Chernikov struct chashentry; 57174b941f0SAlexander V. Chernikov 57274b941f0SAlexander V. Chernikov SLIST_HEAD(chashbhead, chashentry); 57374b941f0SAlexander V. Chernikov 57474b941f0SAlexander V. Chernikov struct chash_cfg { 57574b941f0SAlexander V. Chernikov struct chashbhead *head4; 57674b941f0SAlexander V. Chernikov struct chashbhead *head6; 57774b941f0SAlexander V. Chernikov size_t size4; 57874b941f0SAlexander V. Chernikov size_t size6; 579ce2817b5SAlexander V. Chernikov size_t items4; 580ce2817b5SAlexander V. Chernikov size_t items6; 58174b941f0SAlexander V. Chernikov uint8_t mask4; 58274b941f0SAlexander V. Chernikov uint8_t mask6; 58374b941f0SAlexander V. Chernikov }; 58474b941f0SAlexander V. Chernikov 58574b941f0SAlexander V. Chernikov struct chashentry { 58674b941f0SAlexander V. Chernikov SLIST_ENTRY(chashentry) next; 58774b941f0SAlexander V. Chernikov uint32_t value; 58874b941f0SAlexander V. Chernikov uint32_t type; 58974b941f0SAlexander V. Chernikov union { 59074b941f0SAlexander V. Chernikov uint32_t a4; /* Host format */ 59174b941f0SAlexander V. Chernikov struct in6_addr a6; /* Network format */ 59274b941f0SAlexander V. Chernikov } a; 59374b941f0SAlexander V. Chernikov }; 59474b941f0SAlexander V. Chernikov 59574b941f0SAlexander V. Chernikov static __inline uint32_t 59674b941f0SAlexander V. Chernikov hash_ip(uint32_t addr, int hsize) 59774b941f0SAlexander V. Chernikov { 59874b941f0SAlexander V. Chernikov 59974b941f0SAlexander V. Chernikov return (addr % (hsize - 1)); 60074b941f0SAlexander V. Chernikov } 60174b941f0SAlexander V. Chernikov 60274b941f0SAlexander V. Chernikov static __inline uint32_t 60374b941f0SAlexander V. Chernikov hash_ip6(struct in6_addr *addr6, int hsize) 60474b941f0SAlexander V. Chernikov { 60574b941f0SAlexander V. Chernikov uint32_t i; 60674b941f0SAlexander V. Chernikov 60774b941f0SAlexander V. Chernikov i = addr6->s6_addr32[0] ^ addr6->s6_addr32[1] ^ 60874b941f0SAlexander V. Chernikov addr6->s6_addr32[2] ^ addr6->s6_addr32[3]; 60974b941f0SAlexander V. Chernikov 61074b941f0SAlexander V. Chernikov return (i % (hsize - 1)); 61174b941f0SAlexander V. Chernikov } 61274b941f0SAlexander V. Chernikov 61374b941f0SAlexander V. Chernikov 61474b941f0SAlexander V. Chernikov static __inline uint16_t 61574b941f0SAlexander V. Chernikov hash_ip64(struct in6_addr *addr6, int hsize) 61674b941f0SAlexander V. Chernikov { 61774b941f0SAlexander V. Chernikov uint32_t i; 61874b941f0SAlexander V. Chernikov 61974b941f0SAlexander V. Chernikov i = addr6->s6_addr32[0] ^ addr6->s6_addr32[1]; 62074b941f0SAlexander V. Chernikov 62174b941f0SAlexander V. Chernikov return (i % (hsize - 1)); 62274b941f0SAlexander V. Chernikov } 62374b941f0SAlexander V. Chernikov 62474b941f0SAlexander V. Chernikov 62574b941f0SAlexander V. Chernikov static __inline uint32_t 62674b941f0SAlexander V. Chernikov hash_ip6_slow(struct in6_addr *addr6, void *key, int mask, int hsize) 62774b941f0SAlexander V. Chernikov { 62874b941f0SAlexander V. Chernikov struct in6_addr mask6; 62974b941f0SAlexander V. Chernikov 63074b941f0SAlexander V. Chernikov ipv6_writemask(&mask6, mask); 63174b941f0SAlexander V. Chernikov memcpy(addr6, key, sizeof(struct in6_addr)); 63274b941f0SAlexander V. Chernikov APPLY_MASK(addr6, &mask6); 63374b941f0SAlexander V. Chernikov return (hash_ip6(addr6, hsize)); 63474b941f0SAlexander V. Chernikov } 63574b941f0SAlexander V. Chernikov 63674b941f0SAlexander V. Chernikov static __inline uint32_t 63774b941f0SAlexander V. Chernikov hash_ip6_al(struct in6_addr *addr6, void *key, int mask, int hsize) 63874b941f0SAlexander V. Chernikov { 63974b941f0SAlexander V. Chernikov uint64_t *paddr; 64074b941f0SAlexander V. Chernikov 64174b941f0SAlexander V. Chernikov paddr = (uint64_t *)addr6; 64274b941f0SAlexander V. Chernikov *paddr = 0; 64374b941f0SAlexander V. Chernikov *(paddr + 1) = 0; 64474b941f0SAlexander V. Chernikov memcpy(addr6, key, mask); 64574b941f0SAlexander V. Chernikov return (hash_ip6(addr6, hsize)); 64674b941f0SAlexander V. Chernikov } 64774b941f0SAlexander V. Chernikov 64874b941f0SAlexander V. Chernikov static int 64974b941f0SAlexander V. Chernikov ta_lookup_chash_slow(struct table_info *ti, void *key, uint32_t keylen, 65074b941f0SAlexander V. Chernikov uint32_t *val) 65174b941f0SAlexander V. Chernikov { 65274b941f0SAlexander V. Chernikov struct chashbhead *head; 65374b941f0SAlexander V. Chernikov struct chashentry *ent; 65474b941f0SAlexander V. Chernikov uint16_t hash, hsize; 65574b941f0SAlexander V. Chernikov uint8_t imask; 65674b941f0SAlexander V. Chernikov 65774b941f0SAlexander V. Chernikov if (keylen == sizeof(in_addr_t)) { 65874b941f0SAlexander V. Chernikov head = (struct chashbhead *)ti->state; 65974b941f0SAlexander V. Chernikov imask = ti->data >> 24; 66074b941f0SAlexander V. Chernikov hsize = 1 << ((ti->data & 0xFFFF) >> 8); 66174b941f0SAlexander V. Chernikov uint32_t a; 66274b941f0SAlexander V. Chernikov a = ntohl(*((in_addr_t *)key)); 66374b941f0SAlexander V. Chernikov a = a >> imask; 66474b941f0SAlexander V. Chernikov hash = hash_ip(a, hsize); 66574b941f0SAlexander V. Chernikov SLIST_FOREACH(ent, &head[hash], next) { 66674b941f0SAlexander V. Chernikov if (ent->a.a4 == a) { 66774b941f0SAlexander V. Chernikov *val = ent->value; 66874b941f0SAlexander V. Chernikov return (1); 66974b941f0SAlexander V. Chernikov } 67074b941f0SAlexander V. Chernikov } 67174b941f0SAlexander V. Chernikov } else { 67274b941f0SAlexander V. Chernikov /* IPv6: worst scenario: non-round mask */ 67374b941f0SAlexander V. Chernikov struct in6_addr addr6; 67474b941f0SAlexander V. Chernikov head = (struct chashbhead *)ti->xstate; 67574b941f0SAlexander V. Chernikov imask = (ti->data & 0xFF0000) >> 16; 67674b941f0SAlexander V. Chernikov hsize = 1 << (ti->data & 0xFF); 67774b941f0SAlexander V. Chernikov hash = hash_ip6_slow(&addr6, key, imask, hsize); 67874b941f0SAlexander V. Chernikov SLIST_FOREACH(ent, &head[hash], next) { 67974b941f0SAlexander V. Chernikov if (memcmp(&ent->a.a6, &addr6, 16) == 0) { 68074b941f0SAlexander V. Chernikov *val = ent->value; 68174b941f0SAlexander V. Chernikov return (1); 68274b941f0SAlexander V. Chernikov } 68374b941f0SAlexander V. Chernikov } 68474b941f0SAlexander V. Chernikov } 68574b941f0SAlexander V. Chernikov 68674b941f0SAlexander V. Chernikov return (0); 68774b941f0SAlexander V. Chernikov } 68874b941f0SAlexander V. Chernikov 68974b941f0SAlexander V. Chernikov static int 69074b941f0SAlexander V. Chernikov ta_lookup_chash_aligned(struct table_info *ti, void *key, uint32_t keylen, 69174b941f0SAlexander V. Chernikov uint32_t *val) 69274b941f0SAlexander V. Chernikov { 69374b941f0SAlexander V. Chernikov struct chashbhead *head; 69474b941f0SAlexander V. Chernikov struct chashentry *ent; 69574b941f0SAlexander V. Chernikov uint16_t hash, hsize; 69674b941f0SAlexander V. Chernikov uint8_t imask; 69774b941f0SAlexander V. Chernikov 69874b941f0SAlexander V. Chernikov if (keylen == sizeof(in_addr_t)) { 69974b941f0SAlexander V. Chernikov head = (struct chashbhead *)ti->state; 70074b941f0SAlexander V. Chernikov imask = ti->data >> 24; 70174b941f0SAlexander V. Chernikov hsize = 1 << ((ti->data & 0xFFFF) >> 8); 70274b941f0SAlexander V. Chernikov uint32_t a; 70374b941f0SAlexander V. Chernikov a = ntohl(*((in_addr_t *)key)); 70474b941f0SAlexander V. Chernikov a = a >> imask; 70574b941f0SAlexander V. Chernikov hash = hash_ip(a, hsize); 70674b941f0SAlexander V. Chernikov SLIST_FOREACH(ent, &head[hash], next) { 70774b941f0SAlexander V. Chernikov if (ent->a.a4 == a) { 70874b941f0SAlexander V. Chernikov *val = ent->value; 70974b941f0SAlexander V. Chernikov return (1); 71074b941f0SAlexander V. Chernikov } 71174b941f0SAlexander V. Chernikov } 71274b941f0SAlexander V. Chernikov } else { 71374b941f0SAlexander V. Chernikov /* IPv6: aligned to 8bit mask */ 71474b941f0SAlexander V. Chernikov struct in6_addr addr6; 71574b941f0SAlexander V. Chernikov uint64_t *paddr, *ptmp; 71674b941f0SAlexander V. Chernikov head = (struct chashbhead *)ti->xstate; 71774b941f0SAlexander V. Chernikov imask = (ti->data & 0xFF0000) >> 16; 71874b941f0SAlexander V. Chernikov hsize = 1 << (ti->data & 0xFF); 71974b941f0SAlexander V. Chernikov 72074b941f0SAlexander V. Chernikov hash = hash_ip6_al(&addr6, key, imask, hsize); 72174b941f0SAlexander V. Chernikov paddr = (uint64_t *)&addr6; 72274b941f0SAlexander V. Chernikov SLIST_FOREACH(ent, &head[hash], next) { 72374b941f0SAlexander V. Chernikov ptmp = (uint64_t *)&ent->a.a6; 72474b941f0SAlexander V. Chernikov if (paddr[0] == ptmp[0] && paddr[1] == ptmp[1]) { 72574b941f0SAlexander V. Chernikov *val = ent->value; 72674b941f0SAlexander V. Chernikov return (1); 72774b941f0SAlexander V. Chernikov } 72874b941f0SAlexander V. Chernikov } 72974b941f0SAlexander V. Chernikov } 73074b941f0SAlexander V. Chernikov 73174b941f0SAlexander V. Chernikov return (0); 73274b941f0SAlexander V. Chernikov } 73374b941f0SAlexander V. Chernikov 73474b941f0SAlexander V. Chernikov static int 73574b941f0SAlexander V. Chernikov ta_lookup_chash_64(struct table_info *ti, void *key, uint32_t keylen, 73674b941f0SAlexander V. Chernikov uint32_t *val) 73774b941f0SAlexander V. Chernikov { 73874b941f0SAlexander V. Chernikov struct chashbhead *head; 73974b941f0SAlexander V. Chernikov struct chashentry *ent; 74074b941f0SAlexander V. Chernikov uint16_t hash, hsize; 74174b941f0SAlexander V. Chernikov uint8_t imask; 74274b941f0SAlexander V. Chernikov 74374b941f0SAlexander V. Chernikov if (keylen == sizeof(in_addr_t)) { 74474b941f0SAlexander V. Chernikov head = (struct chashbhead *)ti->state; 74574b941f0SAlexander V. Chernikov imask = ti->data >> 24; 74674b941f0SAlexander V. Chernikov hsize = 1 << ((ti->data & 0xFFFF) >> 8); 74774b941f0SAlexander V. Chernikov uint32_t a; 74874b941f0SAlexander V. Chernikov a = ntohl(*((in_addr_t *)key)); 74974b941f0SAlexander V. Chernikov a = a >> imask; 75074b941f0SAlexander V. Chernikov hash = hash_ip(a, hsize); 75174b941f0SAlexander V. Chernikov SLIST_FOREACH(ent, &head[hash], next) { 75274b941f0SAlexander V. Chernikov if (ent->a.a4 == a) { 75374b941f0SAlexander V. Chernikov *val = ent->value; 75474b941f0SAlexander V. Chernikov return (1); 75574b941f0SAlexander V. Chernikov } 75674b941f0SAlexander V. Chernikov } 75774b941f0SAlexander V. Chernikov } else { 75874b941f0SAlexander V. Chernikov /* IPv6: /64 */ 75974b941f0SAlexander V. Chernikov uint64_t a6, *paddr; 76074b941f0SAlexander V. Chernikov head = (struct chashbhead *)ti->xstate; 76174b941f0SAlexander V. Chernikov paddr = (uint64_t *)key; 76274b941f0SAlexander V. Chernikov hsize = 1 << (ti->data & 0xFF); 76374b941f0SAlexander V. Chernikov a6 = *paddr; 76474b941f0SAlexander V. Chernikov hash = hash_ip64((struct in6_addr *)key, hsize); 76574b941f0SAlexander V. Chernikov SLIST_FOREACH(ent, &head[hash], next) { 76674b941f0SAlexander V. Chernikov paddr = (uint64_t *)&ent->a.a6; 76774b941f0SAlexander V. Chernikov if (a6 == *paddr) { 76874b941f0SAlexander V. Chernikov *val = ent->value; 76974b941f0SAlexander V. Chernikov return (1); 77074b941f0SAlexander V. Chernikov } 77174b941f0SAlexander V. Chernikov } 77274b941f0SAlexander V. Chernikov } 77374b941f0SAlexander V. Chernikov 77474b941f0SAlexander V. Chernikov return (0); 77574b941f0SAlexander V. Chernikov } 77674b941f0SAlexander V. Chernikov 77774b941f0SAlexander V. Chernikov static int 77874b941f0SAlexander V. Chernikov chash_parse_opts(struct chash_cfg *ccfg, char *data) 77974b941f0SAlexander V. Chernikov { 78074b941f0SAlexander V. Chernikov char *pdel, *pend, *s; 78174b941f0SAlexander V. Chernikov int mask4, mask6; 78274b941f0SAlexander V. Chernikov 78374b941f0SAlexander V. Chernikov mask4 = ccfg->mask4; 78474b941f0SAlexander V. Chernikov mask6 = ccfg->mask6; 78574b941f0SAlexander V. Chernikov 78674b941f0SAlexander V. Chernikov if (data == NULL) 78774b941f0SAlexander V. Chernikov return (0); 78874b941f0SAlexander V. Chernikov if ((pdel = strchr(data, ' ')) == NULL) 78974b941f0SAlexander V. Chernikov return (0); 79074b941f0SAlexander V. Chernikov while (*pdel == ' ') 79174b941f0SAlexander V. Chernikov pdel++; 79274b941f0SAlexander V. Chernikov if (strncmp(pdel, "masks=", 6) != 0) 79374b941f0SAlexander V. Chernikov return (EINVAL); 79474b941f0SAlexander V. Chernikov if ((s = strchr(pdel, ' ')) != NULL) 79574b941f0SAlexander V. Chernikov *s++ = '\0'; 79674b941f0SAlexander V. Chernikov 79774b941f0SAlexander V. Chernikov pdel += 6; 79874b941f0SAlexander V. Chernikov /* Need /XX[,/YY] */ 79974b941f0SAlexander V. Chernikov if (*pdel++ != '/') 80074b941f0SAlexander V. Chernikov return (EINVAL); 80174b941f0SAlexander V. Chernikov mask4 = strtol(pdel, &pend, 10); 80274b941f0SAlexander V. Chernikov if (*pend == ',') { 80374b941f0SAlexander V. Chernikov /* ,/YY */ 80474b941f0SAlexander V. Chernikov pdel = pend + 1; 80574b941f0SAlexander V. Chernikov if (*pdel++ != '/') 80674b941f0SAlexander V. Chernikov return (EINVAL); 80774b941f0SAlexander V. Chernikov mask6 = strtol(pdel, &pend, 10); 80874b941f0SAlexander V. Chernikov if (*pend != '\0') 80974b941f0SAlexander V. Chernikov return (EINVAL); 81074b941f0SAlexander V. Chernikov } else if (*pend != '\0') 81174b941f0SAlexander V. Chernikov return (EINVAL); 81274b941f0SAlexander V. Chernikov 81374b941f0SAlexander V. Chernikov if (mask4 < 0 || mask4 > 32 || mask6 < 0 || mask6 > 128) 81474b941f0SAlexander V. Chernikov return (EINVAL); 81574b941f0SAlexander V. Chernikov 81674b941f0SAlexander V. Chernikov ccfg->mask4 = mask4; 81774b941f0SAlexander V. Chernikov ccfg->mask6 = mask6; 81874b941f0SAlexander V. Chernikov 81974b941f0SAlexander V. Chernikov return (0); 82074b941f0SAlexander V. Chernikov } 82174b941f0SAlexander V. Chernikov 82274b941f0SAlexander V. Chernikov static void 82374b941f0SAlexander V. Chernikov ta_print_chash_config(void *ta_state, struct table_info *ti, char *buf, 82474b941f0SAlexander V. Chernikov size_t bufsize) 82574b941f0SAlexander V. Chernikov { 82674b941f0SAlexander V. Chernikov struct chash_cfg *ccfg; 82774b941f0SAlexander V. Chernikov 82874b941f0SAlexander V. Chernikov ccfg = (struct chash_cfg *)ta_state; 82974b941f0SAlexander V. Chernikov 83074b941f0SAlexander V. Chernikov if (ccfg->mask4 != 32 || ccfg->mask6 != 128) 83174b941f0SAlexander V. Chernikov snprintf(buf, bufsize, "%s masks=/%d,/%d", "cidr:hash", 83274b941f0SAlexander V. Chernikov ccfg->mask4, ccfg->mask6); 83374b941f0SAlexander V. Chernikov else 83474b941f0SAlexander V. Chernikov snprintf(buf, bufsize, "%s", "cidr:hash"); 83574b941f0SAlexander V. Chernikov } 83674b941f0SAlexander V. Chernikov 837914bffb6SAlexander V. Chernikov static int 838914bffb6SAlexander V. Chernikov log2(uint32_t v) 839914bffb6SAlexander V. Chernikov { 840914bffb6SAlexander V. Chernikov uint32_t r; 841914bffb6SAlexander V. Chernikov 842914bffb6SAlexander V. Chernikov r = 0; 843914bffb6SAlexander V. Chernikov while (v >>= 1) 844914bffb6SAlexander V. Chernikov r++; 845914bffb6SAlexander V. Chernikov 846914bffb6SAlexander V. Chernikov return (r); 847914bffb6SAlexander V. Chernikov } 84874b941f0SAlexander V. Chernikov 84974b941f0SAlexander V. Chernikov /* 85074b941f0SAlexander V. Chernikov * New table. 85174b941f0SAlexander V. Chernikov * We assume 'data' to be either NULL or the following format: 85274b941f0SAlexander V. Chernikov * 'cidr:hash [masks=/32[,/128]]' 85374b941f0SAlexander V. Chernikov */ 85474b941f0SAlexander V. Chernikov static int 85574b941f0SAlexander V. Chernikov ta_init_chash(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti, 856914bffb6SAlexander V. Chernikov char *data, uint8_t tflags) 85774b941f0SAlexander V. Chernikov { 85874b941f0SAlexander V. Chernikov int error, i; 859914bffb6SAlexander V. Chernikov uint32_t hsize; 86074b941f0SAlexander V. Chernikov struct chash_cfg *ccfg; 86174b941f0SAlexander V. Chernikov 86274b941f0SAlexander V. Chernikov ccfg = malloc(sizeof(struct chash_cfg), M_IPFW, M_WAITOK | M_ZERO); 86374b941f0SAlexander V. Chernikov 86474b941f0SAlexander V. Chernikov ccfg->mask4 = 32; 86574b941f0SAlexander V. Chernikov ccfg->mask6 = 128; 86674b941f0SAlexander V. Chernikov 86774b941f0SAlexander V. Chernikov if ((error = chash_parse_opts(ccfg, data)) != 0) { 86874b941f0SAlexander V. Chernikov free(ccfg, M_IPFW); 86974b941f0SAlexander V. Chernikov return (error); 87074b941f0SAlexander V. Chernikov } 87174b941f0SAlexander V. Chernikov 872914bffb6SAlexander V. Chernikov ccfg->size4 = 128; 873914bffb6SAlexander V. Chernikov ccfg->size6 = 128; 87474b941f0SAlexander V. Chernikov 87574b941f0SAlexander V. Chernikov ccfg->head4 = malloc(sizeof(struct chashbhead) * ccfg->size4, M_IPFW, 87674b941f0SAlexander V. Chernikov M_WAITOK | M_ZERO); 87774b941f0SAlexander V. Chernikov ccfg->head6 = malloc(sizeof(struct chashbhead) * ccfg->size6, M_IPFW, 87874b941f0SAlexander V. Chernikov M_WAITOK | M_ZERO); 87974b941f0SAlexander V. Chernikov for (i = 0; i < ccfg->size4; i++) 88074b941f0SAlexander V. Chernikov SLIST_INIT(&ccfg->head4[i]); 88174b941f0SAlexander V. Chernikov for (i = 0; i < ccfg->size6; i++) 88274b941f0SAlexander V. Chernikov SLIST_INIT(&ccfg->head6[i]); 88374b941f0SAlexander V. Chernikov 88474b941f0SAlexander V. Chernikov 88574b941f0SAlexander V. Chernikov *ta_state = ccfg; 88674b941f0SAlexander V. Chernikov ti->state = ccfg->head4; 88774b941f0SAlexander V. Chernikov ti->xstate = ccfg->head6; 88874b941f0SAlexander V. Chernikov 88974b941f0SAlexander V. Chernikov /* Store data depending on v6 mask length */ 890914bffb6SAlexander V. Chernikov hsize = log2(ccfg->size4) << 8 | log2(ccfg->size6); 89174b941f0SAlexander V. Chernikov if (ccfg->mask6 == 64) { 89274b941f0SAlexander V. Chernikov ti->data = (32 - ccfg->mask4) << 24 | (128 - ccfg->mask6) << 16| 893914bffb6SAlexander V. Chernikov hsize; 89474b941f0SAlexander V. Chernikov ti->lookup = ta_lookup_chash_64; 89574b941f0SAlexander V. Chernikov } else if ((ccfg->mask6 % 8) == 0) { 89674b941f0SAlexander V. Chernikov ti->data = (32 - ccfg->mask4) << 24 | 897914bffb6SAlexander V. Chernikov ccfg->mask6 << 13 | hsize; 89874b941f0SAlexander V. Chernikov ti->lookup = ta_lookup_chash_aligned; 89974b941f0SAlexander V. Chernikov } else { 90074b941f0SAlexander V. Chernikov /* don't do that! */ 90174b941f0SAlexander V. Chernikov ti->data = (32 - ccfg->mask4) << 24 | 902914bffb6SAlexander V. Chernikov ccfg->mask6 << 16 | hsize; 90374b941f0SAlexander V. Chernikov ti->lookup = ta_lookup_chash_slow; 90474b941f0SAlexander V. Chernikov } 90574b941f0SAlexander V. Chernikov 90674b941f0SAlexander V. Chernikov return (0); 90774b941f0SAlexander V. Chernikov } 90874b941f0SAlexander V. Chernikov 90974b941f0SAlexander V. Chernikov static void 91074b941f0SAlexander V. Chernikov ta_destroy_chash(void *ta_state, struct table_info *ti) 91174b941f0SAlexander V. Chernikov { 91274b941f0SAlexander V. Chernikov struct chash_cfg *ccfg; 91374b941f0SAlexander V. Chernikov struct chashentry *ent, *ent_next; 91474b941f0SAlexander V. Chernikov int i; 91574b941f0SAlexander V. Chernikov 91674b941f0SAlexander V. Chernikov ccfg = (struct chash_cfg *)ta_state; 91774b941f0SAlexander V. Chernikov 91874b941f0SAlexander V. Chernikov for (i = 0; i < ccfg->size4; i++) 91974b941f0SAlexander V. Chernikov SLIST_FOREACH_SAFE(ent, &ccfg->head4[i], next, ent_next) 92074b941f0SAlexander V. Chernikov free(ent, M_IPFW_TBL); 92174b941f0SAlexander V. Chernikov 92274b941f0SAlexander V. Chernikov for (i = 0; i < ccfg->size6; i++) 92374b941f0SAlexander V. Chernikov SLIST_FOREACH_SAFE(ent, &ccfg->head6[i], next, ent_next) 92474b941f0SAlexander V. Chernikov free(ent, M_IPFW_TBL); 92574b941f0SAlexander V. Chernikov 92674b941f0SAlexander V. Chernikov free(ccfg->head4, M_IPFW); 92774b941f0SAlexander V. Chernikov free(ccfg->head6, M_IPFW); 928ce2817b5SAlexander V. Chernikov 929ce2817b5SAlexander V. Chernikov free(ccfg, M_IPFW); 93074b941f0SAlexander V. Chernikov } 93174b941f0SAlexander V. Chernikov 93274b941f0SAlexander V. Chernikov static int 93374b941f0SAlexander V. Chernikov ta_dump_chash_tentry(void *ta_state, struct table_info *ti, void *e, 93474b941f0SAlexander V. Chernikov ipfw_obj_tentry *tent) 93574b941f0SAlexander V. Chernikov { 93674b941f0SAlexander V. Chernikov struct chash_cfg *ccfg; 93774b941f0SAlexander V. Chernikov struct chashentry *ent; 93874b941f0SAlexander V. Chernikov 93974b941f0SAlexander V. Chernikov ccfg = (struct chash_cfg *)ta_state; 94074b941f0SAlexander V. Chernikov ent = (struct chashentry *)e; 94174b941f0SAlexander V. Chernikov 94274b941f0SAlexander V. Chernikov if (ent->type == AF_INET) { 94374b941f0SAlexander V. Chernikov tent->k.addr.s_addr = htonl(ent->a.a4 << (32 - ccfg->mask4)); 94474b941f0SAlexander V. Chernikov tent->masklen = ccfg->mask4; 94574b941f0SAlexander V. Chernikov tent->subtype = AF_INET; 94674b941f0SAlexander V. Chernikov tent->value = ent->value; 94774b941f0SAlexander V. Chernikov #ifdef INET6 94874b941f0SAlexander V. Chernikov } else { 94974b941f0SAlexander V. Chernikov memcpy(&tent->k, &ent->a.a6, sizeof(struct in6_addr)); 95074b941f0SAlexander V. Chernikov tent->masklen = ccfg->mask6; 95174b941f0SAlexander V. Chernikov tent->subtype = AF_INET6; 95274b941f0SAlexander V. Chernikov tent->value = ent->value; 95374b941f0SAlexander V. Chernikov #endif 95474b941f0SAlexander V. Chernikov } 95574b941f0SAlexander V. Chernikov 95674b941f0SAlexander V. Chernikov return (0); 95774b941f0SAlexander V. Chernikov } 95874b941f0SAlexander V. Chernikov 959ce2817b5SAlexander V. Chernikov static uint32_t 960ce2817b5SAlexander V. Chernikov hash_ent(struct chashentry *ent, int af, int mlen, uint32_t size) 961ce2817b5SAlexander V. Chernikov { 962ce2817b5SAlexander V. Chernikov uint32_t hash; 963ce2817b5SAlexander V. Chernikov 964ce2817b5SAlexander V. Chernikov if (af == AF_INET) { 965ce2817b5SAlexander V. Chernikov hash = hash_ip(ent->a.a4, size); 966ce2817b5SAlexander V. Chernikov } else { 967ce2817b5SAlexander V. Chernikov if (mlen == 64) 968ce2817b5SAlexander V. Chernikov hash = hash_ip64(&ent->a.a6, size); 969ce2817b5SAlexander V. Chernikov else 970ce2817b5SAlexander V. Chernikov hash = hash_ip6(&ent->a.a6, size); 971ce2817b5SAlexander V. Chernikov } 972ce2817b5SAlexander V. Chernikov 973ce2817b5SAlexander V. Chernikov return (hash); 974ce2817b5SAlexander V. Chernikov } 975ce2817b5SAlexander V. Chernikov 976ce2817b5SAlexander V. Chernikov static int 977ce2817b5SAlexander V. Chernikov tei_to_chash_ent(struct tentry_info *tei, struct chashentry *ent) 978ce2817b5SAlexander V. Chernikov { 979ce2817b5SAlexander V. Chernikov struct in6_addr mask6; 980ce2817b5SAlexander V. Chernikov int mlen; 981ce2817b5SAlexander V. Chernikov 982ce2817b5SAlexander V. Chernikov 983ce2817b5SAlexander V. Chernikov mlen = tei->masklen; 984ce2817b5SAlexander V. Chernikov 985ce2817b5SAlexander V. Chernikov if (tei->subtype == AF_INET) { 986ce2817b5SAlexander V. Chernikov #ifdef INET 987ce2817b5SAlexander V. Chernikov if (mlen > 32) 988ce2817b5SAlexander V. Chernikov return (EINVAL); 989ce2817b5SAlexander V. Chernikov ent->type = AF_INET; 990ce2817b5SAlexander V. Chernikov 991ce2817b5SAlexander V. Chernikov /* Calculate masked address */ 992ce2817b5SAlexander V. Chernikov ent->a.a4 = ntohl(*((in_addr_t *)tei->paddr)) >> (32 - mlen); 993ce2817b5SAlexander V. Chernikov #endif 994ce2817b5SAlexander V. Chernikov #ifdef INET6 995ce2817b5SAlexander V. Chernikov } else if (tei->subtype == AF_INET6) { 996ce2817b5SAlexander V. Chernikov /* IPv6 case */ 997ce2817b5SAlexander V. Chernikov if (mlen > 128) 998ce2817b5SAlexander V. Chernikov return (EINVAL); 999ce2817b5SAlexander V. Chernikov ent->type = AF_INET6; 1000ce2817b5SAlexander V. Chernikov 1001ce2817b5SAlexander V. Chernikov ipv6_writemask(&mask6, mlen); 1002ce2817b5SAlexander V. Chernikov memcpy(&ent->a.a6, tei->paddr, sizeof(struct in6_addr)); 1003ce2817b5SAlexander V. Chernikov APPLY_MASK(&ent->a.a6, &mask6); 1004ce2817b5SAlexander V. Chernikov #endif 1005ce2817b5SAlexander V. Chernikov } else { 1006ce2817b5SAlexander V. Chernikov /* Unknown CIDR type */ 1007ce2817b5SAlexander V. Chernikov return (EINVAL); 1008ce2817b5SAlexander V. Chernikov } 1009ce2817b5SAlexander V. Chernikov ent->value = tei->value; 1010ce2817b5SAlexander V. Chernikov 1011ce2817b5SAlexander V. Chernikov return (0); 1012ce2817b5SAlexander V. Chernikov } 1013ce2817b5SAlexander V. Chernikov 1014ce2817b5SAlexander V. Chernikov 101574b941f0SAlexander V. Chernikov static int 1016914bffb6SAlexander V. Chernikov ta_find_chash_tentry(void *ta_state, struct table_info *ti, 1017914bffb6SAlexander V. Chernikov ipfw_obj_tentry *tent) 101874b941f0SAlexander V. Chernikov { 1019ce2817b5SAlexander V. Chernikov struct chash_cfg *ccfg; 1020ce2817b5SAlexander V. Chernikov struct chashbhead *head; 1021ce2817b5SAlexander V. Chernikov struct chashentry ent, *tmp; 1022ce2817b5SAlexander V. Chernikov struct tentry_info tei; 1023ce2817b5SAlexander V. Chernikov int error; 1024ce2817b5SAlexander V. Chernikov uint32_t hash; 102574b941f0SAlexander V. Chernikov 1026ce2817b5SAlexander V. Chernikov ccfg = (struct chash_cfg *)ta_state; 1027ce2817b5SAlexander V. Chernikov 1028ce2817b5SAlexander V. Chernikov memset(&ent, 0, sizeof(ent)); 1029ce2817b5SAlexander V. Chernikov memset(&tei, 0, sizeof(tei)); 1030ce2817b5SAlexander V. Chernikov 1031914bffb6SAlexander V. Chernikov if (tent->subtype == AF_INET) { 1032914bffb6SAlexander V. Chernikov tei.paddr = &tent->k.addr; 1033ce2817b5SAlexander V. Chernikov tei.masklen = ccfg->mask4; 1034ce2817b5SAlexander V. Chernikov tei.subtype = AF_INET; 103574b941f0SAlexander V. Chernikov 1036ce2817b5SAlexander V. Chernikov if ((error = tei_to_chash_ent(&tei, &ent)) != 0) 1037ce2817b5SAlexander V. Chernikov return (error); 1038ce2817b5SAlexander V. Chernikov 1039ce2817b5SAlexander V. Chernikov head = ccfg->head4; 1040ce2817b5SAlexander V. Chernikov hash = hash_ent(&ent, AF_INET, ccfg->mask4, ccfg->size4); 1041ce2817b5SAlexander V. Chernikov /* Check for existence */ 1042ce2817b5SAlexander V. Chernikov SLIST_FOREACH(tmp, &head[hash], next) { 1043ce2817b5SAlexander V. Chernikov if (tmp->a.a4 != ent.a.a4) 1044ce2817b5SAlexander V. Chernikov continue; 1045ce2817b5SAlexander V. Chernikov 1046ce2817b5SAlexander V. Chernikov ta_dump_chash_tentry(ta_state, ti, tmp, tent); 104774b941f0SAlexander V. Chernikov return (0); 104874b941f0SAlexander V. Chernikov } 1049ce2817b5SAlexander V. Chernikov } else { 1050914bffb6SAlexander V. Chernikov tei.paddr = &tent->k.addr6; 1051ce2817b5SAlexander V. Chernikov tei.masklen = ccfg->mask6; 1052ce2817b5SAlexander V. Chernikov tei.subtype = AF_INET6; 1053ce2817b5SAlexander V. Chernikov 1054ce2817b5SAlexander V. Chernikov if ((error = tei_to_chash_ent(&tei, &ent)) != 0) 1055ce2817b5SAlexander V. Chernikov return (error); 1056ce2817b5SAlexander V. Chernikov 1057ce2817b5SAlexander V. Chernikov head = ccfg->head6; 1058ce2817b5SAlexander V. Chernikov hash = hash_ent(&ent, AF_INET6, ccfg->mask6, ccfg->size6); 1059ce2817b5SAlexander V. Chernikov /* Check for existence */ 1060ce2817b5SAlexander V. Chernikov SLIST_FOREACH(tmp, &head[hash], next) { 1061ce2817b5SAlexander V. Chernikov if (memcmp(&tmp->a.a6, &ent.a.a6, 16) != 0) 1062ce2817b5SAlexander V. Chernikov continue; 1063ce2817b5SAlexander V. Chernikov ta_dump_chash_tentry(ta_state, ti, tmp, tent); 1064ce2817b5SAlexander V. Chernikov return (0); 1065ce2817b5SAlexander V. Chernikov } 1066ce2817b5SAlexander V. Chernikov } 1067ce2817b5SAlexander V. Chernikov 106874b941f0SAlexander V. Chernikov return (ENOENT); 106974b941f0SAlexander V. Chernikov } 107074b941f0SAlexander V. Chernikov 107174b941f0SAlexander V. Chernikov static void 107274b941f0SAlexander V. Chernikov ta_foreach_chash(void *ta_state, struct table_info *ti, ta_foreach_f *f, 107374b941f0SAlexander V. Chernikov void *arg) 107474b941f0SAlexander V. Chernikov { 107574b941f0SAlexander V. Chernikov struct chash_cfg *ccfg; 107674b941f0SAlexander V. Chernikov struct chashentry *ent, *ent_next; 107774b941f0SAlexander V. Chernikov int i; 107874b941f0SAlexander V. Chernikov 107974b941f0SAlexander V. Chernikov ccfg = (struct chash_cfg *)ta_state; 108074b941f0SAlexander V. Chernikov 108174b941f0SAlexander V. Chernikov for (i = 0; i < ccfg->size4; i++) 108274b941f0SAlexander V. Chernikov SLIST_FOREACH_SAFE(ent, &ccfg->head4[i], next, ent_next) 108374b941f0SAlexander V. Chernikov f(ent, arg); 108474b941f0SAlexander V. Chernikov 108574b941f0SAlexander V. Chernikov for (i = 0; i < ccfg->size6; i++) 108674b941f0SAlexander V. Chernikov SLIST_FOREACH_SAFE(ent, &ccfg->head6[i], next, ent_next) 108774b941f0SAlexander V. Chernikov f(ent, arg); 108874b941f0SAlexander V. Chernikov } 108974b941f0SAlexander V. Chernikov 109074b941f0SAlexander V. Chernikov 109174b941f0SAlexander V. Chernikov struct ta_buf_chash 109274b941f0SAlexander V. Chernikov { 109374b941f0SAlexander V. Chernikov void *ent_ptr; 1094ce2817b5SAlexander V. Chernikov struct chashentry ent; 109574b941f0SAlexander V. Chernikov }; 109674b941f0SAlexander V. Chernikov 109774b941f0SAlexander V. Chernikov static int 109874b941f0SAlexander V. Chernikov ta_prepare_add_chash(struct ip_fw_chain *ch, struct tentry_info *tei, 109974b941f0SAlexander V. Chernikov void *ta_buf) 110074b941f0SAlexander V. Chernikov { 110174b941f0SAlexander V. Chernikov struct ta_buf_chash *tb; 110274b941f0SAlexander V. Chernikov struct chashentry *ent; 1103ce2817b5SAlexander V. Chernikov int error; 110474b941f0SAlexander V. Chernikov 110574b941f0SAlexander V. Chernikov tb = (struct ta_buf_chash *)ta_buf; 110674b941f0SAlexander V. Chernikov memset(tb, 0, sizeof(struct ta_buf_chash)); 110774b941f0SAlexander V. Chernikov 110874b941f0SAlexander V. Chernikov ent = malloc(sizeof(*ent), M_IPFW_TBL, M_WAITOK | M_ZERO); 110974b941f0SAlexander V. Chernikov 1110ce2817b5SAlexander V. Chernikov error = tei_to_chash_ent(tei, ent); 1111ce2817b5SAlexander V. Chernikov if (error != 0) { 1112ce2817b5SAlexander V. Chernikov free(ent, M_IPFW_TBL); 1113ce2817b5SAlexander V. Chernikov return (error); 111474b941f0SAlexander V. Chernikov } 1115ce2817b5SAlexander V. Chernikov tb->ent_ptr = ent; 111674b941f0SAlexander V. Chernikov 111774b941f0SAlexander V. Chernikov return (0); 111874b941f0SAlexander V. Chernikov } 111974b941f0SAlexander V. Chernikov 112074b941f0SAlexander V. Chernikov static int 112174b941f0SAlexander V. Chernikov ta_add_chash(void *ta_state, struct table_info *ti, struct tentry_info *tei, 112274b941f0SAlexander V. Chernikov void *ta_buf, uint64_t *pflags, uint32_t *pnum) 112374b941f0SAlexander V. Chernikov { 112474b941f0SAlexander V. Chernikov struct chash_cfg *ccfg; 112574b941f0SAlexander V. Chernikov struct chashbhead *head; 112674b941f0SAlexander V. Chernikov struct chashentry *ent, *tmp; 112774b941f0SAlexander V. Chernikov struct ta_buf_chash *tb; 112874b941f0SAlexander V. Chernikov int exists; 112974b941f0SAlexander V. Chernikov uint32_t hash; 113074b941f0SAlexander V. Chernikov 113174b941f0SAlexander V. Chernikov ccfg = (struct chash_cfg *)ta_state; 113274b941f0SAlexander V. Chernikov tb = (struct ta_buf_chash *)ta_buf; 113374b941f0SAlexander V. Chernikov ent = (struct chashentry *)tb->ent_ptr; 113474b941f0SAlexander V. Chernikov hash = 0; 113574b941f0SAlexander V. Chernikov exists = 0; 113674b941f0SAlexander V. Chernikov 113774b941f0SAlexander V. Chernikov if (tei->subtype == AF_INET) { 113874b941f0SAlexander V. Chernikov if (tei->masklen != ccfg->mask4) 113974b941f0SAlexander V. Chernikov return (EINVAL); 114074b941f0SAlexander V. Chernikov head = ccfg->head4; 1141ce2817b5SAlexander V. Chernikov hash = hash_ent(ent, AF_INET, ccfg->mask4, ccfg->size4); 1142ce2817b5SAlexander V. Chernikov 114374b941f0SAlexander V. Chernikov /* Check for existence */ 114474b941f0SAlexander V. Chernikov SLIST_FOREACH(tmp, &head[hash], next) { 114574b941f0SAlexander V. Chernikov if (tmp->a.a4 == ent->a.a4) { 114674b941f0SAlexander V. Chernikov exists = 1; 114774b941f0SAlexander V. Chernikov break; 114874b941f0SAlexander V. Chernikov } 114974b941f0SAlexander V. Chernikov } 115074b941f0SAlexander V. Chernikov } else { 115174b941f0SAlexander V. Chernikov if (tei->masklen != ccfg->mask6) 115274b941f0SAlexander V. Chernikov return (EINVAL); 115374b941f0SAlexander V. Chernikov head = ccfg->head6; 1154ce2817b5SAlexander V. Chernikov hash = hash_ent(ent, AF_INET6, ccfg->mask6, ccfg->size6); 115574b941f0SAlexander V. Chernikov /* Check for existence */ 115674b941f0SAlexander V. Chernikov SLIST_FOREACH(tmp, &head[hash], next) { 1157ce2817b5SAlexander V. Chernikov if (memcmp(&tmp->a.a6, &ent->a.a6, 16) == 0) { 115874b941f0SAlexander V. Chernikov exists = 1; 115974b941f0SAlexander V. Chernikov break; 116074b941f0SAlexander V. Chernikov } 116174b941f0SAlexander V. Chernikov } 116274b941f0SAlexander V. Chernikov } 116374b941f0SAlexander V. Chernikov 116474b941f0SAlexander V. Chernikov if (exists == 1) { 116574b941f0SAlexander V. Chernikov if ((tei->flags & TEI_FLAGS_UPDATE) == 0) 116674b941f0SAlexander V. Chernikov return (EEXIST); 116774b941f0SAlexander V. Chernikov /* Record already exists. Update value if we're asked to */ 116874b941f0SAlexander V. Chernikov tmp->value = tei->value; 116974b941f0SAlexander V. Chernikov /* Indicate that update has happened instead of addition */ 117074b941f0SAlexander V. Chernikov tei->flags |= TEI_FLAGS_UPDATED; 117174b941f0SAlexander V. Chernikov *pnum = 0; 117274b941f0SAlexander V. Chernikov } else { 117374b941f0SAlexander V. Chernikov SLIST_INSERT_HEAD(&head[hash], ent, next); 117474b941f0SAlexander V. Chernikov tb->ent_ptr = NULL; 117574b941f0SAlexander V. Chernikov *pnum = 1; 1176ce2817b5SAlexander V. Chernikov 1177ce2817b5SAlexander V. Chernikov /* Update counters and check if we need to grow hash */ 1178ce2817b5SAlexander V. Chernikov if (tei->subtype == AF_INET) { 1179ce2817b5SAlexander V. Chernikov ccfg->items4++; 1180ce2817b5SAlexander V. Chernikov if (ccfg->items4 > ccfg->size4 && ccfg->size4 < 65536) 1181ce2817b5SAlexander V. Chernikov *pflags = (ccfg->size4 * 2) | (1UL << 32); 1182ce2817b5SAlexander V. Chernikov } else { 1183ce2817b5SAlexander V. Chernikov ccfg->items6++; 1184ce2817b5SAlexander V. Chernikov if (ccfg->items6 > ccfg->size6 && ccfg->size6 < 65536) 1185ce2817b5SAlexander V. Chernikov *pflags = ccfg->size6 * 2; 1186ce2817b5SAlexander V. Chernikov } 118774b941f0SAlexander V. Chernikov } 118874b941f0SAlexander V. Chernikov 118974b941f0SAlexander V. Chernikov return (0); 119074b941f0SAlexander V. Chernikov } 119174b941f0SAlexander V. Chernikov 119274b941f0SAlexander V. Chernikov static int 119374b941f0SAlexander V. Chernikov ta_prepare_del_chash(struct ip_fw_chain *ch, struct tentry_info *tei, 119474b941f0SAlexander V. Chernikov void *ta_buf) 119574b941f0SAlexander V. Chernikov { 119674b941f0SAlexander V. Chernikov struct ta_buf_chash *tb; 119774b941f0SAlexander V. Chernikov 119874b941f0SAlexander V. Chernikov tb = (struct ta_buf_chash *)ta_buf; 119974b941f0SAlexander V. Chernikov memset(tb, 0, sizeof(struct ta_buf_chash)); 120074b941f0SAlexander V. Chernikov 1201ce2817b5SAlexander V. Chernikov return (tei_to_chash_ent(tei, &tb->ent)); 120274b941f0SAlexander V. Chernikov } 120374b941f0SAlexander V. Chernikov 120474b941f0SAlexander V. Chernikov static int 120574b941f0SAlexander V. Chernikov ta_del_chash(void *ta_state, struct table_info *ti, struct tentry_info *tei, 120674b941f0SAlexander V. Chernikov void *ta_buf, uint64_t *pflags, uint32_t *pnum) 120774b941f0SAlexander V. Chernikov { 120874b941f0SAlexander V. Chernikov struct chash_cfg *ccfg; 120974b941f0SAlexander V. Chernikov struct chashbhead *head; 1210ce2817b5SAlexander V. Chernikov struct chashentry *ent, *tmp_next, *dent; 121174b941f0SAlexander V. Chernikov struct ta_buf_chash *tb; 121274b941f0SAlexander V. Chernikov uint32_t hash; 121374b941f0SAlexander V. Chernikov 121474b941f0SAlexander V. Chernikov ccfg = (struct chash_cfg *)ta_state; 121574b941f0SAlexander V. Chernikov tb = (struct ta_buf_chash *)ta_buf; 1216ce2817b5SAlexander V. Chernikov dent = &tb->ent; 121774b941f0SAlexander V. Chernikov 121874b941f0SAlexander V. Chernikov if (tei->subtype == AF_INET) { 121974b941f0SAlexander V. Chernikov if (tei->masklen != ccfg->mask4) 122074b941f0SAlexander V. Chernikov return (EINVAL); 122174b941f0SAlexander V. Chernikov head = ccfg->head4; 1222ce2817b5SAlexander V. Chernikov hash = hash_ent(dent, AF_INET, ccfg->mask4, ccfg->size4); 122374b941f0SAlexander V. Chernikov 122474b941f0SAlexander V. Chernikov SLIST_FOREACH_SAFE(ent, &head[hash], next, tmp_next) { 1225ce2817b5SAlexander V. Chernikov if (ent->a.a4 == dent->a.a4) { 122674b941f0SAlexander V. Chernikov SLIST_REMOVE(&head[hash], ent, chashentry,next); 122774b941f0SAlexander V. Chernikov *pnum = 1; 1228ce2817b5SAlexander V. Chernikov ccfg->items4--; 122974b941f0SAlexander V. Chernikov return (0); 123074b941f0SAlexander V. Chernikov } 123174b941f0SAlexander V. Chernikov } 123274b941f0SAlexander V. Chernikov } else { 123374b941f0SAlexander V. Chernikov if (tei->masklen != ccfg->mask6) 123474b941f0SAlexander V. Chernikov return (EINVAL); 123574b941f0SAlexander V. Chernikov head = ccfg->head6; 1236ce2817b5SAlexander V. Chernikov hash = hash_ent(dent, AF_INET6, ccfg->mask6, ccfg->size6); 123774b941f0SAlexander V. Chernikov SLIST_FOREACH_SAFE(ent, &head[hash], next, tmp_next) { 1238ce2817b5SAlexander V. Chernikov if (memcmp(&ent->a.a6, &dent->a.a6, 16) == 0) { 123974b941f0SAlexander V. Chernikov SLIST_REMOVE(&head[hash], ent, chashentry,next); 1240ce2817b5SAlexander V. Chernikov ccfg->items6--; 124174b941f0SAlexander V. Chernikov *pnum = 1; 124274b941f0SAlexander V. Chernikov return (0); 124374b941f0SAlexander V. Chernikov } 124474b941f0SAlexander V. Chernikov } 124574b941f0SAlexander V. Chernikov } 124674b941f0SAlexander V. Chernikov 124774b941f0SAlexander V. Chernikov return (ENOENT); 124874b941f0SAlexander V. Chernikov } 124974b941f0SAlexander V. Chernikov 125074b941f0SAlexander V. Chernikov static void 125174b941f0SAlexander V. Chernikov ta_flush_chash_entry(struct ip_fw_chain *ch, struct tentry_info *tei, 125274b941f0SAlexander V. Chernikov void *ta_buf) 125374b941f0SAlexander V. Chernikov { 125474b941f0SAlexander V. Chernikov struct ta_buf_chash *tb; 125574b941f0SAlexander V. Chernikov 125674b941f0SAlexander V. Chernikov tb = (struct ta_buf_chash *)ta_buf; 125774b941f0SAlexander V. Chernikov 125874b941f0SAlexander V. Chernikov if (tb->ent_ptr != NULL) 125974b941f0SAlexander V. Chernikov free(tb->ent_ptr, M_IPFW_TBL); 126074b941f0SAlexander V. Chernikov } 126174b941f0SAlexander V. Chernikov 1262ce2817b5SAlexander V. Chernikov /* 1263ce2817b5SAlexander V. Chernikov * Hash growing callbacks. 1264ce2817b5SAlexander V. Chernikov */ 1265ce2817b5SAlexander V. Chernikov 1266ce2817b5SAlexander V. Chernikov struct mod_item { 1267ce2817b5SAlexander V. Chernikov void *main_ptr; 1268ce2817b5SAlexander V. Chernikov size_t size; 1269ce2817b5SAlexander V. Chernikov }; 1270ce2817b5SAlexander V. Chernikov 1271ce2817b5SAlexander V. Chernikov /* 1272ce2817b5SAlexander V. Chernikov * Allocate new, larger chash. 1273ce2817b5SAlexander V. Chernikov */ 1274ce2817b5SAlexander V. Chernikov static int 1275ce2817b5SAlexander V. Chernikov ta_prepare_mod_chash(void *ta_buf, uint64_t *pflags) 1276ce2817b5SAlexander V. Chernikov { 1277ce2817b5SAlexander V. Chernikov struct mod_item *mi; 1278ce2817b5SAlexander V. Chernikov struct chashbhead *head; 1279ce2817b5SAlexander V. Chernikov int i; 1280ce2817b5SAlexander V. Chernikov 1281ce2817b5SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 1282ce2817b5SAlexander V. Chernikov 1283ce2817b5SAlexander V. Chernikov memset(mi, 0, sizeof(struct mod_item)); 1284ce2817b5SAlexander V. Chernikov mi->size = *pflags & 0xFFFFFFFF; 1285ce2817b5SAlexander V. Chernikov head = malloc(sizeof(struct chashbhead) * mi->size, M_IPFW, 1286ce2817b5SAlexander V. Chernikov M_WAITOK | M_ZERO); 1287ce2817b5SAlexander V. Chernikov for (i = 0; i < mi->size; i++) 1288ce2817b5SAlexander V. Chernikov SLIST_INIT(&head[i]); 1289ce2817b5SAlexander V. Chernikov 1290ce2817b5SAlexander V. Chernikov mi->main_ptr = head; 1291ce2817b5SAlexander V. Chernikov 1292ce2817b5SAlexander V. Chernikov return (0); 1293ce2817b5SAlexander V. Chernikov } 1294ce2817b5SAlexander V. Chernikov 1295ce2817b5SAlexander V. Chernikov /* 1296ce2817b5SAlexander V. Chernikov * Copy data from old runtime array to new one. 1297ce2817b5SAlexander V. Chernikov */ 1298ce2817b5SAlexander V. Chernikov static int 1299ce2817b5SAlexander V. Chernikov ta_fill_mod_chash(void *ta_state, struct table_info *ti, void *ta_buf, 1300ce2817b5SAlexander V. Chernikov uint64_t *pflags) 1301ce2817b5SAlexander V. Chernikov { 1302ce2817b5SAlexander V. Chernikov 1303ce2817b5SAlexander V. Chernikov /* In is not possible to do rehash if we're not holidng WLOCK. */ 1304ce2817b5SAlexander V. Chernikov return (0); 1305ce2817b5SAlexander V. Chernikov } 1306ce2817b5SAlexander V. Chernikov 1307ce2817b5SAlexander V. Chernikov 1308ce2817b5SAlexander V. Chernikov /* 1309ce2817b5SAlexander V. Chernikov * Switch old & new arrays. 1310ce2817b5SAlexander V. Chernikov */ 1311ce2817b5SAlexander V. Chernikov static int 1312ce2817b5SAlexander V. Chernikov ta_modify_chash(void *ta_state, struct table_info *ti, void *ta_buf, 1313ce2817b5SAlexander V. Chernikov uint64_t pflags) 1314ce2817b5SAlexander V. Chernikov { 1315ce2817b5SAlexander V. Chernikov struct mod_item *mi; 1316ce2817b5SAlexander V. Chernikov struct chash_cfg *ccfg; 1317ce2817b5SAlexander V. Chernikov struct chashbhead *old_head, *new_head; 1318ce2817b5SAlexander V. Chernikov struct chashentry *ent, *ent_next; 1319ce2817b5SAlexander V. Chernikov int af, i, mlen; 1320ce2817b5SAlexander V. Chernikov uint32_t nhash; 1321ce2817b5SAlexander V. Chernikov size_t old_size; 1322ce2817b5SAlexander V. Chernikov 1323ce2817b5SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 1324ce2817b5SAlexander V. Chernikov ccfg = (struct chash_cfg *)ta_state; 1325ce2817b5SAlexander V. Chernikov 1326ce2817b5SAlexander V. Chernikov /* Check which hash we need to grow and do we still need that */ 1327ce2817b5SAlexander V. Chernikov if ((pflags >> 32) == 1) { 1328ce2817b5SAlexander V. Chernikov old_size = ccfg->size4; 1329ce2817b5SAlexander V. Chernikov old_head = ti->state; 1330ce2817b5SAlexander V. Chernikov mlen = ccfg->mask4; 1331ce2817b5SAlexander V. Chernikov af = AF_INET; 1332ce2817b5SAlexander V. Chernikov } else { 1333ce2817b5SAlexander V. Chernikov old_size = ccfg->size6; 1334ce2817b5SAlexander V. Chernikov old_head = ti->xstate; 1335ce2817b5SAlexander V. Chernikov mlen = ccfg->mask6; 1336ce2817b5SAlexander V. Chernikov af = AF_INET6; 1337ce2817b5SAlexander V. Chernikov } 1338ce2817b5SAlexander V. Chernikov 1339ce2817b5SAlexander V. Chernikov if (old_size >= mi->size) 1340ce2817b5SAlexander V. Chernikov return (0); 1341ce2817b5SAlexander V. Chernikov 1342ce2817b5SAlexander V. Chernikov new_head = (struct chashbhead *)mi->main_ptr; 1343ce2817b5SAlexander V. Chernikov for (i = 0; i < old_size; i++) { 1344ce2817b5SAlexander V. Chernikov SLIST_FOREACH_SAFE(ent, &old_head[i], next, ent_next) { 1345ce2817b5SAlexander V. Chernikov nhash = hash_ent(ent, af, mlen, mi->size); 1346ce2817b5SAlexander V. Chernikov SLIST_INSERT_HEAD(&new_head[nhash], ent, next); 1347ce2817b5SAlexander V. Chernikov } 1348ce2817b5SAlexander V. Chernikov } 1349ce2817b5SAlexander V. Chernikov 1350ce2817b5SAlexander V. Chernikov if (af == AF_INET) { 1351ce2817b5SAlexander V. Chernikov ti->state = new_head; 1352ce2817b5SAlexander V. Chernikov ccfg->head4 = new_head; 1353ce2817b5SAlexander V. Chernikov ccfg->size4 = mi->size; 1354ce2817b5SAlexander V. Chernikov } else { 1355ce2817b5SAlexander V. Chernikov ti->xstate = new_head; 1356ce2817b5SAlexander V. Chernikov ccfg->head6 = new_head; 1357ce2817b5SAlexander V. Chernikov ccfg->size6 = mi->size; 1358ce2817b5SAlexander V. Chernikov } 1359ce2817b5SAlexander V. Chernikov 1360914bffb6SAlexander V. Chernikov ti->data = (ti->data & 0xFFFFFFFF00000000) | log2(ccfg->size4) << 8 | 1361914bffb6SAlexander V. Chernikov log2(ccfg->size6); 1362914bffb6SAlexander V. Chernikov 1363ce2817b5SAlexander V. Chernikov mi->main_ptr = old_head; 1364ce2817b5SAlexander V. Chernikov 1365ce2817b5SAlexander V. Chernikov return (0); 1366ce2817b5SAlexander V. Chernikov } 1367ce2817b5SAlexander V. Chernikov 1368ce2817b5SAlexander V. Chernikov /* 1369ce2817b5SAlexander V. Chernikov * Free unneded array. 1370ce2817b5SAlexander V. Chernikov */ 1371ce2817b5SAlexander V. Chernikov static void 1372ce2817b5SAlexander V. Chernikov ta_flush_mod_chash(void *ta_buf) 1373ce2817b5SAlexander V. Chernikov { 1374ce2817b5SAlexander V. Chernikov struct mod_item *mi; 1375ce2817b5SAlexander V. Chernikov 1376ce2817b5SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 1377ce2817b5SAlexander V. Chernikov if (mi->main_ptr != NULL) 1378ce2817b5SAlexander V. Chernikov free(mi->main_ptr, M_IPFW); 1379ce2817b5SAlexander V. Chernikov } 1380ce2817b5SAlexander V. Chernikov 138174b941f0SAlexander V. Chernikov struct table_algo cidr_hash = { 138274b941f0SAlexander V. Chernikov .name = "cidr:hash", 13839d099b4fSAlexander V. Chernikov .type = IPFW_TABLE_CIDR, 138457a1cf95SAlexander V. Chernikov .ta_buf_size = sizeof(struct ta_buf_chash), 138574b941f0SAlexander V. Chernikov .init = ta_init_chash, 138674b941f0SAlexander V. Chernikov .destroy = ta_destroy_chash, 138774b941f0SAlexander V. Chernikov .prepare_add = ta_prepare_add_chash, 138874b941f0SAlexander V. Chernikov .prepare_del = ta_prepare_del_chash, 138974b941f0SAlexander V. Chernikov .add = ta_add_chash, 139074b941f0SAlexander V. Chernikov .del = ta_del_chash, 139174b941f0SAlexander V. Chernikov .flush_entry = ta_flush_chash_entry, 139274b941f0SAlexander V. Chernikov .foreach = ta_foreach_chash, 139374b941f0SAlexander V. Chernikov .dump_tentry = ta_dump_chash_tentry, 139474b941f0SAlexander V. Chernikov .find_tentry = ta_find_chash_tentry, 139574b941f0SAlexander V. Chernikov .print_config = ta_print_chash_config, 1396ce2817b5SAlexander V. Chernikov .prepare_mod = ta_prepare_mod_chash, 1397ce2817b5SAlexander V. Chernikov .fill_mod = ta_fill_mod_chash, 1398ce2817b5SAlexander V. Chernikov .modify = ta_modify_chash, 1399ce2817b5SAlexander V. Chernikov .flush_mod = ta_flush_mod_chash, 140074b941f0SAlexander V. Chernikov }; 140174b941f0SAlexander V. Chernikov 140274b941f0SAlexander V. Chernikov 140374b941f0SAlexander V. Chernikov /* 140468394ec8SAlexander V. Chernikov * Iface table cmds. 140568394ec8SAlexander V. Chernikov * 140668394ec8SAlexander V. Chernikov * Implementation: 140768394ec8SAlexander V. Chernikov * 140868394ec8SAlexander V. Chernikov * Runtime part: 140968394ec8SAlexander V. Chernikov * - sorted array of "struct ifidx" pointed by ti->state. 1410b23d5de9SAlexander V. Chernikov * Array is allocated with rounding up to IFIDX_CHUNK. Only existing 141168394ec8SAlexander V. Chernikov * interfaces are stored in array, however its allocated size is 141268394ec8SAlexander V. Chernikov * sufficient to hold all table records if needed. 141368394ec8SAlexander V. Chernikov * - current array size is stored in ti->data 141468394ec8SAlexander V. Chernikov * 141568394ec8SAlexander V. Chernikov * Table data: 141668394ec8SAlexander V. Chernikov * - "struct iftable_cfg" is allocated to store table state (ta_state). 141768394ec8SAlexander V. Chernikov * - All table records are stored inside namedobj instance. 14189f7d47b0SAlexander V. Chernikov * 14199f7d47b0SAlexander V. Chernikov */ 14209f7d47b0SAlexander V. Chernikov 142168394ec8SAlexander V. Chernikov struct ifidx { 142268394ec8SAlexander V. Chernikov uint16_t kidx; 142368394ec8SAlexander V. Chernikov uint16_t spare; 142468394ec8SAlexander V. Chernikov uint32_t value; 142568394ec8SAlexander V. Chernikov }; 142668394ec8SAlexander V. Chernikov 142768394ec8SAlexander V. Chernikov struct iftable_cfg; 142868394ec8SAlexander V. Chernikov 142968394ec8SAlexander V. Chernikov struct ifentry { 143068394ec8SAlexander V. Chernikov struct named_object no; 143168394ec8SAlexander V. Chernikov struct ipfw_ifc ic; 143268394ec8SAlexander V. Chernikov struct iftable_cfg *icfg; 143368394ec8SAlexander V. Chernikov uint32_t value; 143468394ec8SAlexander V. Chernikov int linked; 143568394ec8SAlexander V. Chernikov }; 143668394ec8SAlexander V. Chernikov 143768394ec8SAlexander V. Chernikov struct iftable_cfg { 143868394ec8SAlexander V. Chernikov struct namedobj_instance *ii; 143968394ec8SAlexander V. Chernikov struct ip_fw_chain *ch; 144068394ec8SAlexander V. Chernikov struct table_info *ti; 144168394ec8SAlexander V. Chernikov void *main_ptr; 144268394ec8SAlexander V. Chernikov size_t size; /* Number of items allocated in array */ 144368394ec8SAlexander V. Chernikov size_t count; /* Number of all items */ 144468394ec8SAlexander V. Chernikov size_t used; /* Number of items _active_ now */ 144568394ec8SAlexander V. Chernikov }; 144668394ec8SAlexander V. Chernikov 144768394ec8SAlexander V. Chernikov #define IFIDX_CHUNK 16 144868394ec8SAlexander V. Chernikov 144968394ec8SAlexander V. Chernikov int compare_ifidx(const void *k, const void *v); 145068394ec8SAlexander V. Chernikov static void if_notifier(struct ip_fw_chain *ch, void *cbdata, uint16_t ifindex); 145168394ec8SAlexander V. Chernikov 145268394ec8SAlexander V. Chernikov int 145368394ec8SAlexander V. Chernikov compare_ifidx(const void *k, const void *v) 145468394ec8SAlexander V. Chernikov { 145568394ec8SAlexander V. Chernikov struct ifidx *ifidx; 145668394ec8SAlexander V. Chernikov uint16_t key; 145768394ec8SAlexander V. Chernikov 145868394ec8SAlexander V. Chernikov key = *((uint16_t *)k); 145968394ec8SAlexander V. Chernikov ifidx = (struct ifidx *)v; 146068394ec8SAlexander V. Chernikov 146168394ec8SAlexander V. Chernikov if (key < ifidx->kidx) 146268394ec8SAlexander V. Chernikov return (-1); 146368394ec8SAlexander V. Chernikov else if (key > ifidx->kidx) 146468394ec8SAlexander V. Chernikov return (1); 146568394ec8SAlexander V. Chernikov 146668394ec8SAlexander V. Chernikov return (0); 146768394ec8SAlexander V. Chernikov } 146868394ec8SAlexander V. Chernikov 146968394ec8SAlexander V. Chernikov /* 147068394ec8SAlexander V. Chernikov * Adds item @item with key @key into ascending-sorted array @base. 147168394ec8SAlexander V. Chernikov * Assumes @base has enough additional storage. 147268394ec8SAlexander V. Chernikov * 147368394ec8SAlexander V. Chernikov * Returns 1 on success, 0 on duplicate key. 147468394ec8SAlexander V. Chernikov */ 14759f7d47b0SAlexander V. Chernikov static int 147668394ec8SAlexander V. Chernikov badd(const void *key, void *item, void *base, size_t nmemb, 147768394ec8SAlexander V. Chernikov size_t size, int (*compar) (const void *, const void *)) 147868394ec8SAlexander V. Chernikov { 147968394ec8SAlexander V. Chernikov int min, max, mid, shift, res; 148068394ec8SAlexander V. Chernikov caddr_t paddr; 148168394ec8SAlexander V. Chernikov 148268394ec8SAlexander V. Chernikov if (nmemb == 0) { 148368394ec8SAlexander V. Chernikov memcpy(base, item, size); 148468394ec8SAlexander V. Chernikov return (1); 148568394ec8SAlexander V. Chernikov } 148668394ec8SAlexander V. Chernikov 148768394ec8SAlexander V. Chernikov /* Binary search */ 148868394ec8SAlexander V. Chernikov min = 0; 148968394ec8SAlexander V. Chernikov max = nmemb - 1; 149068394ec8SAlexander V. Chernikov mid = 0; 149168394ec8SAlexander V. Chernikov while (min <= max) { 149268394ec8SAlexander V. Chernikov mid = (min + max) / 2; 149368394ec8SAlexander V. Chernikov res = compar(key, (const void *)((caddr_t)base + mid * size)); 149468394ec8SAlexander V. Chernikov if (res == 0) 149568394ec8SAlexander V. Chernikov return (0); 149668394ec8SAlexander V. Chernikov 149768394ec8SAlexander V. Chernikov if (res > 0) 149868394ec8SAlexander V. Chernikov min = mid + 1; 149968394ec8SAlexander V. Chernikov else 150068394ec8SAlexander V. Chernikov max = mid - 1; 150168394ec8SAlexander V. Chernikov } 150268394ec8SAlexander V. Chernikov 150368394ec8SAlexander V. Chernikov /* Item not found. */ 150468394ec8SAlexander V. Chernikov res = compar(key, (const void *)((caddr_t)base + mid * size)); 150568394ec8SAlexander V. Chernikov if (res > 0) 150668394ec8SAlexander V. Chernikov shift = mid + 1; 150768394ec8SAlexander V. Chernikov else 150868394ec8SAlexander V. Chernikov shift = mid; 150968394ec8SAlexander V. Chernikov 151068394ec8SAlexander V. Chernikov paddr = (caddr_t)base + shift * size; 151168394ec8SAlexander V. Chernikov if (nmemb > shift) 151268394ec8SAlexander V. Chernikov memmove(paddr + size, paddr, (nmemb - shift) * size); 151368394ec8SAlexander V. Chernikov 151468394ec8SAlexander V. Chernikov memcpy(paddr, item, size); 151568394ec8SAlexander V. Chernikov 151668394ec8SAlexander V. Chernikov return (1); 151768394ec8SAlexander V. Chernikov } 151868394ec8SAlexander V. Chernikov 151968394ec8SAlexander V. Chernikov /* 152068394ec8SAlexander V. Chernikov * Deletes item with key @key from ascending-sorted array @base. 152168394ec8SAlexander V. Chernikov * 152268394ec8SAlexander V. Chernikov * Returns 1 on success, 0 for non-existent key. 152368394ec8SAlexander V. Chernikov */ 152468394ec8SAlexander V. Chernikov static int 152568394ec8SAlexander V. Chernikov bdel(const void *key, void *base, size_t nmemb, size_t size, 152668394ec8SAlexander V. Chernikov int (*compar) (const void *, const void *)) 152768394ec8SAlexander V. Chernikov { 152868394ec8SAlexander V. Chernikov caddr_t item; 152968394ec8SAlexander V. Chernikov size_t sz; 153068394ec8SAlexander V. Chernikov 153168394ec8SAlexander V. Chernikov item = (caddr_t)bsearch(key, base, nmemb, size, compar); 153268394ec8SAlexander V. Chernikov 153368394ec8SAlexander V. Chernikov if (item == NULL) 153468394ec8SAlexander V. Chernikov return (0); 153568394ec8SAlexander V. Chernikov 153668394ec8SAlexander V. Chernikov sz = (caddr_t)base + nmemb * size - item; 153768394ec8SAlexander V. Chernikov 153868394ec8SAlexander V. Chernikov if (sz > 0) 153968394ec8SAlexander V. Chernikov memmove(item, item + size, sz); 154068394ec8SAlexander V. Chernikov 154168394ec8SAlexander V. Chernikov return (1); 154268394ec8SAlexander V. Chernikov } 154368394ec8SAlexander V. Chernikov 154468394ec8SAlexander V. Chernikov static struct ifidx * 154568394ec8SAlexander V. Chernikov ifidx_find(struct table_info *ti, void *key) 154668394ec8SAlexander V. Chernikov { 154768394ec8SAlexander V. Chernikov struct ifidx *ifi; 154868394ec8SAlexander V. Chernikov 154968394ec8SAlexander V. Chernikov ifi = bsearch(key, ti->state, ti->data, sizeof(struct ifidx), 155068394ec8SAlexander V. Chernikov compare_ifidx); 155168394ec8SAlexander V. Chernikov 155268394ec8SAlexander V. Chernikov return (ifi); 155368394ec8SAlexander V. Chernikov } 155468394ec8SAlexander V. Chernikov 155568394ec8SAlexander V. Chernikov static int 155668394ec8SAlexander V. Chernikov ta_lookup_ifidx(struct table_info *ti, void *key, uint32_t keylen, 15579f7d47b0SAlexander V. Chernikov uint32_t *val) 15589f7d47b0SAlexander V. Chernikov { 155968394ec8SAlexander V. Chernikov struct ifidx *ifi; 15609f7d47b0SAlexander V. Chernikov 156168394ec8SAlexander V. Chernikov ifi = ifidx_find(ti, key); 15629f7d47b0SAlexander V. Chernikov 156368394ec8SAlexander V. Chernikov if (ifi != NULL) { 156468394ec8SAlexander V. Chernikov *val = ifi->value; 15659f7d47b0SAlexander V. Chernikov return (1); 15669f7d47b0SAlexander V. Chernikov } 15679f7d47b0SAlexander V. Chernikov 15689f7d47b0SAlexander V. Chernikov return (0); 15699f7d47b0SAlexander V. Chernikov } 15709f7d47b0SAlexander V. Chernikov 15719f7d47b0SAlexander V. Chernikov static int 157268394ec8SAlexander V. Chernikov ta_init_ifidx(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti, 1573914bffb6SAlexander V. Chernikov char *data, uint8_t tflags) 15749f7d47b0SAlexander V. Chernikov { 157568394ec8SAlexander V. Chernikov struct iftable_cfg *icfg; 15769f7d47b0SAlexander V. Chernikov 157768394ec8SAlexander V. Chernikov icfg = malloc(sizeof(struct iftable_cfg), M_IPFW, M_WAITOK | M_ZERO); 15789f7d47b0SAlexander V. Chernikov 157968394ec8SAlexander V. Chernikov icfg->ii = ipfw_objhash_create(16); 158068394ec8SAlexander V. Chernikov icfg->main_ptr = malloc(sizeof(struct ifidx) * IFIDX_CHUNK, M_IPFW, 158168394ec8SAlexander V. Chernikov M_WAITOK | M_ZERO); 158268394ec8SAlexander V. Chernikov icfg->size = IFIDX_CHUNK; 158368394ec8SAlexander V. Chernikov icfg->ch = ch; 15849f7d47b0SAlexander V. Chernikov 158568394ec8SAlexander V. Chernikov *ta_state = icfg; 158668394ec8SAlexander V. Chernikov ti->state = icfg->main_ptr; 158768394ec8SAlexander V. Chernikov ti->lookup = ta_lookup_ifidx; 15889f7d47b0SAlexander V. Chernikov 15899f7d47b0SAlexander V. Chernikov return (0); 15909f7d47b0SAlexander V. Chernikov } 15919f7d47b0SAlexander V. Chernikov 159268394ec8SAlexander V. Chernikov /* 159368394ec8SAlexander V. Chernikov * Handle tableinfo @ti pointer change (on table array resize). 159468394ec8SAlexander V. Chernikov */ 159568394ec8SAlexander V. Chernikov static void 159668394ec8SAlexander V. Chernikov ta_change_ti_ifidx(void *ta_state, struct table_info *ti) 159768394ec8SAlexander V. Chernikov { 159868394ec8SAlexander V. Chernikov struct iftable_cfg *icfg; 159968394ec8SAlexander V. Chernikov 160068394ec8SAlexander V. Chernikov icfg = (struct iftable_cfg *)ta_state; 160168394ec8SAlexander V. Chernikov icfg->ti = ti; 160268394ec8SAlexander V. Chernikov } 16039f7d47b0SAlexander V. Chernikov 16049f7d47b0SAlexander V. Chernikov static void 160568394ec8SAlexander V. Chernikov destroy_ifidx_locked(struct namedobj_instance *ii, struct named_object *no, 160668394ec8SAlexander V. Chernikov void *arg) 16079f7d47b0SAlexander V. Chernikov { 160868394ec8SAlexander V. Chernikov struct ifentry *ife; 160968394ec8SAlexander V. Chernikov struct ip_fw_chain *ch; 16109f7d47b0SAlexander V. Chernikov 161168394ec8SAlexander V. Chernikov ch = (struct ip_fw_chain *)arg; 161268394ec8SAlexander V. Chernikov ife = (struct ifentry *)no; 161368394ec8SAlexander V. Chernikov 161468394ec8SAlexander V. Chernikov ipfw_iface_del_notify(ch, &ife->ic); 161568394ec8SAlexander V. Chernikov free(ife, M_IPFW_TBL); 16169f7d47b0SAlexander V. Chernikov } 16179f7d47b0SAlexander V. Chernikov 161868394ec8SAlexander V. Chernikov 161968394ec8SAlexander V. Chernikov /* 162068394ec8SAlexander V. Chernikov * Destroys table @ti 162168394ec8SAlexander V. Chernikov */ 162268394ec8SAlexander V. Chernikov static void 162368394ec8SAlexander V. Chernikov ta_destroy_ifidx(void *ta_state, struct table_info *ti) 16249f7d47b0SAlexander V. Chernikov { 162568394ec8SAlexander V. Chernikov struct iftable_cfg *icfg; 162668394ec8SAlexander V. Chernikov struct ip_fw_chain *ch; 162768394ec8SAlexander V. Chernikov 162868394ec8SAlexander V. Chernikov icfg = (struct iftable_cfg *)ta_state; 162968394ec8SAlexander V. Chernikov ch = icfg->ch; 163068394ec8SAlexander V. Chernikov 163168394ec8SAlexander V. Chernikov if (icfg->main_ptr != NULL) 163268394ec8SAlexander V. Chernikov free(icfg->main_ptr, M_IPFW); 163368394ec8SAlexander V. Chernikov 163468394ec8SAlexander V. Chernikov ipfw_objhash_foreach(icfg->ii, destroy_ifidx_locked, ch); 163568394ec8SAlexander V. Chernikov 163668394ec8SAlexander V. Chernikov ipfw_objhash_destroy(icfg->ii); 163768394ec8SAlexander V. Chernikov 163868394ec8SAlexander V. Chernikov free(icfg, M_IPFW); 163968394ec8SAlexander V. Chernikov } 164068394ec8SAlexander V. Chernikov 164168394ec8SAlexander V. Chernikov struct ta_buf_ifidx 164268394ec8SAlexander V. Chernikov { 164368394ec8SAlexander V. Chernikov struct ifentry *ife; 164468394ec8SAlexander V. Chernikov uint32_t value; 16459f7d47b0SAlexander V. Chernikov }; 16469f7d47b0SAlexander V. Chernikov 164768394ec8SAlexander V. Chernikov /* 164868394ec8SAlexander V. Chernikov * Prepare state to add to the table: 164968394ec8SAlexander V. Chernikov * allocate ifentry and reference needed interface. 165068394ec8SAlexander V. Chernikov */ 16519f7d47b0SAlexander V. Chernikov static int 165268394ec8SAlexander V. Chernikov ta_prepare_add_ifidx(struct ip_fw_chain *ch, struct tentry_info *tei, 165368394ec8SAlexander V. Chernikov void *ta_buf) 165468394ec8SAlexander V. Chernikov { 165568394ec8SAlexander V. Chernikov struct ta_buf_ifidx *tb; 165668394ec8SAlexander V. Chernikov char *ifname; 165768394ec8SAlexander V. Chernikov struct ifentry *ife; 165868394ec8SAlexander V. Chernikov 165968394ec8SAlexander V. Chernikov tb = (struct ta_buf_ifidx *)ta_buf; 166074b941f0SAlexander V. Chernikov memset(tb, 0, sizeof(struct ta_buf_ifidx)); 166168394ec8SAlexander V. Chernikov 166268394ec8SAlexander V. Chernikov /* Check if string is terminated */ 166368394ec8SAlexander V. Chernikov ifname = (char *)tei->paddr; 166468394ec8SAlexander V. Chernikov if (strnlen(ifname, IF_NAMESIZE) == IF_NAMESIZE) 166568394ec8SAlexander V. Chernikov return (EINVAL); 166668394ec8SAlexander V. Chernikov 166768394ec8SAlexander V. Chernikov ife = malloc(sizeof(struct ifentry), M_IPFW_TBL, M_WAITOK | M_ZERO); 166868394ec8SAlexander V. Chernikov ife->value = tei->value; 166968394ec8SAlexander V. Chernikov ife->ic.cb = if_notifier; 167068394ec8SAlexander V. Chernikov ife->ic.cbdata = ife; 167168394ec8SAlexander V. Chernikov 167268394ec8SAlexander V. Chernikov if (ipfw_iface_ref(ch, ifname, &ife->ic) != 0) 167368394ec8SAlexander V. Chernikov return (EINVAL); 167468394ec8SAlexander V. Chernikov 167568394ec8SAlexander V. Chernikov /* Use ipfw_iface 'ifname' field as stable storage */ 167668394ec8SAlexander V. Chernikov ife->no.name = ife->ic.iface->ifname; 167768394ec8SAlexander V. Chernikov 167868394ec8SAlexander V. Chernikov tb->ife = ife; 167968394ec8SAlexander V. Chernikov 168068394ec8SAlexander V. Chernikov return (0); 168168394ec8SAlexander V. Chernikov } 168268394ec8SAlexander V. Chernikov 168368394ec8SAlexander V. Chernikov static int 1684adea6201SAlexander V. Chernikov ta_add_ifidx(void *ta_state, struct table_info *ti, struct tentry_info *tei, 1685adea6201SAlexander V. Chernikov void *ta_buf, uint64_t *pflags, uint32_t *pnum) 168668394ec8SAlexander V. Chernikov { 168768394ec8SAlexander V. Chernikov struct iftable_cfg *icfg; 168868394ec8SAlexander V. Chernikov struct ifentry *ife, *tmp; 168968394ec8SAlexander V. Chernikov struct ta_buf_ifidx *tb; 169068394ec8SAlexander V. Chernikov struct ipfw_iface *iif; 169168394ec8SAlexander V. Chernikov struct ifidx *ifi; 169268394ec8SAlexander V. Chernikov char *ifname; 169368394ec8SAlexander V. Chernikov 169468394ec8SAlexander V. Chernikov tb = (struct ta_buf_ifidx *)ta_buf; 169568394ec8SAlexander V. Chernikov ifname = (char *)tei->paddr; 169668394ec8SAlexander V. Chernikov icfg = (struct iftable_cfg *)ta_state; 169768394ec8SAlexander V. Chernikov ife = tb->ife; 169868394ec8SAlexander V. Chernikov 169968394ec8SAlexander V. Chernikov ife->icfg = icfg; 170068394ec8SAlexander V. Chernikov 170168394ec8SAlexander V. Chernikov tmp = (struct ifentry *)ipfw_objhash_lookup_name(icfg->ii, 0, ifname); 170268394ec8SAlexander V. Chernikov 170368394ec8SAlexander V. Chernikov if (tmp != NULL) { 170468394ec8SAlexander V. Chernikov if ((tei->flags & TEI_FLAGS_UPDATE) == 0) 170568394ec8SAlexander V. Chernikov return (EEXIST); 170668394ec8SAlexander V. Chernikov 170768394ec8SAlexander V. Chernikov /* We need to update value */ 170868394ec8SAlexander V. Chernikov iif = tmp->ic.iface; 170968394ec8SAlexander V. Chernikov tmp->value = ife->value; 171068394ec8SAlexander V. Chernikov 171168394ec8SAlexander V. Chernikov if (iif->resolved != 0) { 171268394ec8SAlexander V. Chernikov /* We need to update runtime value, too */ 171368394ec8SAlexander V. Chernikov ifi = ifidx_find(ti, &iif->ifindex); 171468394ec8SAlexander V. Chernikov ifi->value = ife->value; 171568394ec8SAlexander V. Chernikov } 171668394ec8SAlexander V. Chernikov 171768394ec8SAlexander V. Chernikov /* Indicate that update has happened instead of addition */ 171868394ec8SAlexander V. Chernikov tei->flags |= TEI_FLAGS_UPDATED; 1719adea6201SAlexander V. Chernikov *pnum = 0; 172068394ec8SAlexander V. Chernikov return (0); 172168394ec8SAlexander V. Chernikov } 172268394ec8SAlexander V. Chernikov 172368394ec8SAlexander V. Chernikov /* Link to internal list */ 172468394ec8SAlexander V. Chernikov ipfw_objhash_add(icfg->ii, &ife->no); 172568394ec8SAlexander V. Chernikov 172668394ec8SAlexander V. Chernikov /* Link notifier (possible running its callback) */ 172768394ec8SAlexander V. Chernikov ipfw_iface_add_notify(icfg->ch, &ife->ic); 172868394ec8SAlexander V. Chernikov icfg->count++; 172968394ec8SAlexander V. Chernikov 173068394ec8SAlexander V. Chernikov if (icfg->count + 1 == icfg->size) { 173168394ec8SAlexander V. Chernikov /* Notify core we need to grow */ 173268394ec8SAlexander V. Chernikov *pflags = icfg->size + IFIDX_CHUNK; 173368394ec8SAlexander V. Chernikov } 173468394ec8SAlexander V. Chernikov 173568394ec8SAlexander V. Chernikov tb->ife = NULL; 1736adea6201SAlexander V. Chernikov *pnum = 1; 173768394ec8SAlexander V. Chernikov 173868394ec8SAlexander V. Chernikov return (0); 173968394ec8SAlexander V. Chernikov } 174068394ec8SAlexander V. Chernikov 174168394ec8SAlexander V. Chernikov /* 174268394ec8SAlexander V. Chernikov * Prepare to delete key from table. 174368394ec8SAlexander V. Chernikov * Do basic interface name checks. 174468394ec8SAlexander V. Chernikov */ 174568394ec8SAlexander V. Chernikov static int 174668394ec8SAlexander V. Chernikov ta_prepare_del_ifidx(struct ip_fw_chain *ch, struct tentry_info *tei, 174768394ec8SAlexander V. Chernikov void *ta_buf) 17489f7d47b0SAlexander V. Chernikov { 174974b941f0SAlexander V. Chernikov struct ta_buf_ifidx *tb; 1750e0a8b9eeSAlexander V. Chernikov char *ifname; 17519f7d47b0SAlexander V. Chernikov 175274b941f0SAlexander V. Chernikov tb = (struct ta_buf_ifidx *)ta_buf; 175374b941f0SAlexander V. Chernikov memset(tb, 0, sizeof(struct ta_buf_ifidx)); 17549f7d47b0SAlexander V. Chernikov 17559f7d47b0SAlexander V. Chernikov /* Check if string is terminated */ 1756e0a8b9eeSAlexander V. Chernikov ifname = (char *)tei->paddr; 1757e0a8b9eeSAlexander V. Chernikov if (strnlen(ifname, IF_NAMESIZE) == IF_NAMESIZE) 17589f7d47b0SAlexander V. Chernikov return (EINVAL); 17599f7d47b0SAlexander V. Chernikov 17609f7d47b0SAlexander V. Chernikov return (0); 17619f7d47b0SAlexander V. Chernikov } 17629f7d47b0SAlexander V. Chernikov 176368394ec8SAlexander V. Chernikov /* 176468394ec8SAlexander V. Chernikov * Remove key from both configuration list and 176568394ec8SAlexander V. Chernikov * runtime array. Removed interface notification. 176668394ec8SAlexander V. Chernikov */ 17679f7d47b0SAlexander V. Chernikov static int 1768adea6201SAlexander V. Chernikov ta_del_ifidx(void *ta_state, struct table_info *ti, struct tentry_info *tei, 1769adea6201SAlexander V. Chernikov void *ta_buf, uint64_t *pflags, uint32_t *pnum) 17709f7d47b0SAlexander V. Chernikov { 177168394ec8SAlexander V. Chernikov struct iftable_cfg *icfg; 177268394ec8SAlexander V. Chernikov struct ifentry *ife; 177368394ec8SAlexander V. Chernikov struct ta_buf_ifidx *tb; 177468394ec8SAlexander V. Chernikov char *ifname; 177568394ec8SAlexander V. Chernikov uint16_t ifindex; 177668394ec8SAlexander V. Chernikov int res; 17779f7d47b0SAlexander V. Chernikov 177868394ec8SAlexander V. Chernikov tb = (struct ta_buf_ifidx *)ta_buf; 177968394ec8SAlexander V. Chernikov ifname = (char *)tei->paddr; 178068394ec8SAlexander V. Chernikov icfg = (struct iftable_cfg *)ta_state; 178168394ec8SAlexander V. Chernikov ife = tb->ife; 17829f7d47b0SAlexander V. Chernikov 178368394ec8SAlexander V. Chernikov ife = (struct ifentry *)ipfw_objhash_lookup_name(icfg->ii, 0, ifname); 17849f7d47b0SAlexander V. Chernikov 178568394ec8SAlexander V. Chernikov if (ife == NULL) 178681d3153dSAlexander V. Chernikov return (ENOENT); 17879f7d47b0SAlexander V. Chernikov 178868394ec8SAlexander V. Chernikov if (ife->linked != 0) { 178968394ec8SAlexander V. Chernikov /* We have to remove item from runtime */ 179068394ec8SAlexander V. Chernikov ifindex = ife->ic.iface->ifindex; 179168394ec8SAlexander V. Chernikov 179268394ec8SAlexander V. Chernikov res = bdel(&ifindex, icfg->main_ptr, icfg->used, 179368394ec8SAlexander V. Chernikov sizeof(struct ifidx), compare_ifidx); 179468394ec8SAlexander V. Chernikov 179568394ec8SAlexander V. Chernikov KASSERT(res == 1, ("index %d does not exist", ifindex)); 179668394ec8SAlexander V. Chernikov icfg->used--; 179768394ec8SAlexander V. Chernikov ti->data = icfg->used; 179868394ec8SAlexander V. Chernikov ife->linked = 0; 179968394ec8SAlexander V. Chernikov } 180068394ec8SAlexander V. Chernikov 180168394ec8SAlexander V. Chernikov /* Unlink from local list */ 180268394ec8SAlexander V. Chernikov ipfw_objhash_del(icfg->ii, &ife->no); 180368394ec8SAlexander V. Chernikov /* Unlink notifier */ 180468394ec8SAlexander V. Chernikov ipfw_iface_del_notify(icfg->ch, &ife->ic); 180568394ec8SAlexander V. Chernikov 180668394ec8SAlexander V. Chernikov icfg->count--; 180768394ec8SAlexander V. Chernikov 180868394ec8SAlexander V. Chernikov tb->ife = ife; 1809adea6201SAlexander V. Chernikov *pnum = 1; 181068394ec8SAlexander V. Chernikov 18119f7d47b0SAlexander V. Chernikov return (0); 18129f7d47b0SAlexander V. Chernikov } 18139f7d47b0SAlexander V. Chernikov 181468394ec8SAlexander V. Chernikov /* 181568394ec8SAlexander V. Chernikov * Flush deleted entry. 181668394ec8SAlexander V. Chernikov * Drops interface reference and frees entry. 181768394ec8SAlexander V. Chernikov */ 18189f7d47b0SAlexander V. Chernikov static void 181968394ec8SAlexander V. Chernikov ta_flush_ifidx_entry(struct ip_fw_chain *ch, struct tentry_info *tei, 182068394ec8SAlexander V. Chernikov void *ta_buf) 18219f7d47b0SAlexander V. Chernikov { 182268394ec8SAlexander V. Chernikov struct ta_buf_ifidx *tb; 18239f7d47b0SAlexander V. Chernikov 182468394ec8SAlexander V. Chernikov tb = (struct ta_buf_ifidx *)ta_buf; 18259f7d47b0SAlexander V. Chernikov 182668394ec8SAlexander V. Chernikov if (tb->ife != NULL) { 182768394ec8SAlexander V. Chernikov /* Unlink first */ 182868394ec8SAlexander V. Chernikov ipfw_iface_unref(ch, &tb->ife->ic); 182968394ec8SAlexander V. Chernikov free(tb->ife, M_IPFW_TBL); 183068394ec8SAlexander V. Chernikov } 183168394ec8SAlexander V. Chernikov } 183268394ec8SAlexander V. Chernikov 183368394ec8SAlexander V. Chernikov 183468394ec8SAlexander V. Chernikov /* 183568394ec8SAlexander V. Chernikov * Handle interface announce/withdrawal for particular table. 183668394ec8SAlexander V. Chernikov * Every real runtime array modification happens here. 183768394ec8SAlexander V. Chernikov */ 183868394ec8SAlexander V. Chernikov static void 183968394ec8SAlexander V. Chernikov if_notifier(struct ip_fw_chain *ch, void *cbdata, uint16_t ifindex) 184068394ec8SAlexander V. Chernikov { 184168394ec8SAlexander V. Chernikov struct ifentry *ife; 184268394ec8SAlexander V. Chernikov struct ifidx ifi; 184368394ec8SAlexander V. Chernikov struct iftable_cfg *icfg; 184468394ec8SAlexander V. Chernikov struct table_info *ti; 184568394ec8SAlexander V. Chernikov int res; 184668394ec8SAlexander V. Chernikov 184768394ec8SAlexander V. Chernikov ife = (struct ifentry *)cbdata; 184868394ec8SAlexander V. Chernikov icfg = ife->icfg; 184968394ec8SAlexander V. Chernikov ti = icfg->ti; 185068394ec8SAlexander V. Chernikov 185168394ec8SAlexander V. Chernikov KASSERT(ti != NULL, ("ti=NULL, check change_ti handler")); 185268394ec8SAlexander V. Chernikov 185368394ec8SAlexander V. Chernikov if (ife->linked == 0 && ifindex != 0) { 185468394ec8SAlexander V. Chernikov /* Interface announce */ 185568394ec8SAlexander V. Chernikov ifi.kidx = ifindex; 185668394ec8SAlexander V. Chernikov ifi.spare = 0; 185768394ec8SAlexander V. Chernikov ifi.value = ife->value; 185868394ec8SAlexander V. Chernikov res = badd(&ifindex, &ifi, icfg->main_ptr, icfg->used, 185968394ec8SAlexander V. Chernikov sizeof(struct ifidx), compare_ifidx); 186068394ec8SAlexander V. Chernikov KASSERT(res == 1, ("index %d already exists", ifindex)); 186168394ec8SAlexander V. Chernikov icfg->used++; 186268394ec8SAlexander V. Chernikov ti->data = icfg->used; 186368394ec8SAlexander V. Chernikov ife->linked = 1; 186468394ec8SAlexander V. Chernikov } else if (ife->linked != 0 && ifindex == 0) { 186568394ec8SAlexander V. Chernikov /* Interface withdrawal */ 186668394ec8SAlexander V. Chernikov ifindex = ife->ic.iface->ifindex; 186768394ec8SAlexander V. Chernikov 186868394ec8SAlexander V. Chernikov res = bdel(&ifindex, icfg->main_ptr, icfg->used, 186968394ec8SAlexander V. Chernikov sizeof(struct ifidx), compare_ifidx); 187068394ec8SAlexander V. Chernikov 187168394ec8SAlexander V. Chernikov KASSERT(res == 1, ("index %d does not exist", ifindex)); 187268394ec8SAlexander V. Chernikov icfg->used--; 187368394ec8SAlexander V. Chernikov ti->data = icfg->used; 187468394ec8SAlexander V. Chernikov ife->linked = 0; 187568394ec8SAlexander V. Chernikov } 187668394ec8SAlexander V. Chernikov } 187768394ec8SAlexander V. Chernikov 187868394ec8SAlexander V. Chernikov 187968394ec8SAlexander V. Chernikov /* 188068394ec8SAlexander V. Chernikov * Table growing callbacks. 188168394ec8SAlexander V. Chernikov */ 188268394ec8SAlexander V. Chernikov 188368394ec8SAlexander V. Chernikov struct mod_ifidx { 188468394ec8SAlexander V. Chernikov void *main_ptr; 188568394ec8SAlexander V. Chernikov size_t size; 188668394ec8SAlexander V. Chernikov }; 188768394ec8SAlexander V. Chernikov 188868394ec8SAlexander V. Chernikov /* 188968394ec8SAlexander V. Chernikov * Allocate ned, larger runtime ifidx array. 189068394ec8SAlexander V. Chernikov */ 189168394ec8SAlexander V. Chernikov static int 189268394ec8SAlexander V. Chernikov ta_prepare_mod_ifidx(void *ta_buf, uint64_t *pflags) 189368394ec8SAlexander V. Chernikov { 189468394ec8SAlexander V. Chernikov struct mod_ifidx *mi; 189568394ec8SAlexander V. Chernikov 189668394ec8SAlexander V. Chernikov mi = (struct mod_ifidx *)ta_buf; 189768394ec8SAlexander V. Chernikov 189868394ec8SAlexander V. Chernikov memset(mi, 0, sizeof(struct mod_ifidx)); 189968394ec8SAlexander V. Chernikov mi->size = *pflags; 190068394ec8SAlexander V. Chernikov mi->main_ptr = malloc(sizeof(struct ifidx) * mi->size, M_IPFW, 190168394ec8SAlexander V. Chernikov M_WAITOK | M_ZERO); 190268394ec8SAlexander V. Chernikov 190368394ec8SAlexander V. Chernikov return (0); 190468394ec8SAlexander V. Chernikov } 190568394ec8SAlexander V. Chernikov 190668394ec8SAlexander V. Chernikov /* 190768394ec8SAlexander V. Chernikov * Copy data from old runtime array to new one. 190868394ec8SAlexander V. Chernikov */ 190968394ec8SAlexander V. Chernikov static int 191068394ec8SAlexander V. Chernikov ta_fill_mod_ifidx(void *ta_state, struct table_info *ti, void *ta_buf, 191168394ec8SAlexander V. Chernikov uint64_t *pflags) 191268394ec8SAlexander V. Chernikov { 191368394ec8SAlexander V. Chernikov struct mod_ifidx *mi; 191468394ec8SAlexander V. Chernikov struct iftable_cfg *icfg; 191568394ec8SAlexander V. Chernikov 191668394ec8SAlexander V. Chernikov mi = (struct mod_ifidx *)ta_buf; 191768394ec8SAlexander V. Chernikov icfg = (struct iftable_cfg *)ta_state; 191868394ec8SAlexander V. Chernikov 191968394ec8SAlexander V. Chernikov /* Check if we still need to grow array */ 192068394ec8SAlexander V. Chernikov if (icfg->size >= mi->size) { 192168394ec8SAlexander V. Chernikov *pflags = 0; 192268394ec8SAlexander V. Chernikov return (0); 192368394ec8SAlexander V. Chernikov } 192468394ec8SAlexander V. Chernikov 192568394ec8SAlexander V. Chernikov memcpy(mi->main_ptr, icfg->main_ptr, icfg->used * sizeof(struct ifidx)); 192668394ec8SAlexander V. Chernikov 192768394ec8SAlexander V. Chernikov return (0); 192868394ec8SAlexander V. Chernikov } 192968394ec8SAlexander V. Chernikov 193068394ec8SAlexander V. Chernikov /* 193168394ec8SAlexander V. Chernikov * Switch old & new arrays. 193268394ec8SAlexander V. Chernikov */ 193368394ec8SAlexander V. Chernikov static int 193468394ec8SAlexander V. Chernikov ta_modify_ifidx(void *ta_state, struct table_info *ti, void *ta_buf, 193568394ec8SAlexander V. Chernikov uint64_t pflags) 193668394ec8SAlexander V. Chernikov { 193768394ec8SAlexander V. Chernikov struct mod_ifidx *mi; 193868394ec8SAlexander V. Chernikov struct iftable_cfg *icfg; 193968394ec8SAlexander V. Chernikov void *old_ptr; 194068394ec8SAlexander V. Chernikov 194168394ec8SAlexander V. Chernikov mi = (struct mod_ifidx *)ta_buf; 194268394ec8SAlexander V. Chernikov icfg = (struct iftable_cfg *)ta_state; 194368394ec8SAlexander V. Chernikov 194468394ec8SAlexander V. Chernikov old_ptr = icfg->main_ptr; 194568394ec8SAlexander V. Chernikov icfg->main_ptr = mi->main_ptr; 194668394ec8SAlexander V. Chernikov icfg->size = mi->size; 194768394ec8SAlexander V. Chernikov ti->state = icfg->main_ptr; 194868394ec8SAlexander V. Chernikov 194968394ec8SAlexander V. Chernikov mi->main_ptr = old_ptr; 195068394ec8SAlexander V. Chernikov 195168394ec8SAlexander V. Chernikov return (0); 195268394ec8SAlexander V. Chernikov } 195368394ec8SAlexander V. Chernikov 195468394ec8SAlexander V. Chernikov /* 195568394ec8SAlexander V. Chernikov * Free unneded array. 195668394ec8SAlexander V. Chernikov */ 195768394ec8SAlexander V. Chernikov static void 195868394ec8SAlexander V. Chernikov ta_flush_mod_ifidx(void *ta_buf) 195968394ec8SAlexander V. Chernikov { 196068394ec8SAlexander V. Chernikov struct mod_ifidx *mi; 196168394ec8SAlexander V. Chernikov 196268394ec8SAlexander V. Chernikov mi = (struct mod_ifidx *)ta_buf; 196368394ec8SAlexander V. Chernikov if (mi->main_ptr != NULL) 196468394ec8SAlexander V. Chernikov free(mi->main_ptr, M_IPFW); 19659f7d47b0SAlexander V. Chernikov } 19669f7d47b0SAlexander V. Chernikov 19679f7d47b0SAlexander V. Chernikov static int 196868394ec8SAlexander V. Chernikov ta_dump_ifidx_tentry(void *ta_state, struct table_info *ti, void *e, 196981d3153dSAlexander V. Chernikov ipfw_obj_tentry *tent) 19709f7d47b0SAlexander V. Chernikov { 197168394ec8SAlexander V. Chernikov struct ifentry *ife; 19729f7d47b0SAlexander V. Chernikov 197368394ec8SAlexander V. Chernikov ife = (struct ifentry *)e; 197468394ec8SAlexander V. Chernikov 197581d3153dSAlexander V. Chernikov tent->masklen = 8 * IF_NAMESIZE; 197668394ec8SAlexander V. Chernikov memcpy(&tent->k, ife->no.name, IF_NAMESIZE); 197768394ec8SAlexander V. Chernikov tent->value = ife->value; 19789f7d47b0SAlexander V. Chernikov 19799f7d47b0SAlexander V. Chernikov return (0); 19809f7d47b0SAlexander V. Chernikov } 19819f7d47b0SAlexander V. Chernikov 198281d3153dSAlexander V. Chernikov static int 1983914bffb6SAlexander V. Chernikov ta_find_ifidx_tentry(void *ta_state, struct table_info *ti, 1984914bffb6SAlexander V. Chernikov ipfw_obj_tentry *tent) 198581d3153dSAlexander V. Chernikov { 198668394ec8SAlexander V. Chernikov struct iftable_cfg *icfg; 198768394ec8SAlexander V. Chernikov struct ifentry *ife; 198868394ec8SAlexander V. Chernikov char *ifname; 198981d3153dSAlexander V. Chernikov 199068394ec8SAlexander V. Chernikov icfg = (struct iftable_cfg *)ta_state; 1991914bffb6SAlexander V. Chernikov ifname = tent->k.iface; 199281d3153dSAlexander V. Chernikov 199368394ec8SAlexander V. Chernikov if (strnlen(ifname, IF_NAMESIZE) == IF_NAMESIZE) 199468394ec8SAlexander V. Chernikov return (EINVAL); 199581d3153dSAlexander V. Chernikov 199668394ec8SAlexander V. Chernikov ife = (struct ifentry *)ipfw_objhash_lookup_name(icfg->ii, 0, ifname); 199768394ec8SAlexander V. Chernikov 199868394ec8SAlexander V. Chernikov if (ife != NULL) { 199968394ec8SAlexander V. Chernikov ta_dump_ifidx_tentry(ta_state, ti, ife, tent); 200081d3153dSAlexander V. Chernikov return (0); 200181d3153dSAlexander V. Chernikov } 200281d3153dSAlexander V. Chernikov 200381d3153dSAlexander V. Chernikov return (ENOENT); 200481d3153dSAlexander V. Chernikov } 200581d3153dSAlexander V. Chernikov 200668394ec8SAlexander V. Chernikov struct wa_ifidx { 200768394ec8SAlexander V. Chernikov ta_foreach_f *f; 200868394ec8SAlexander V. Chernikov void *arg; 200968394ec8SAlexander V. Chernikov }; 201068394ec8SAlexander V. Chernikov 20119f7d47b0SAlexander V. Chernikov static void 201268394ec8SAlexander V. Chernikov foreach_ifidx(struct namedobj_instance *ii, struct named_object *no, 20139f7d47b0SAlexander V. Chernikov void *arg) 20149f7d47b0SAlexander V. Chernikov { 201568394ec8SAlexander V. Chernikov struct ifentry *ife; 201668394ec8SAlexander V. Chernikov struct wa_ifidx *wa; 20179f7d47b0SAlexander V. Chernikov 201868394ec8SAlexander V. Chernikov ife = (struct ifentry *)no; 201968394ec8SAlexander V. Chernikov wa = (struct wa_ifidx *)arg; 202068394ec8SAlexander V. Chernikov 202168394ec8SAlexander V. Chernikov wa->f(ife, wa->arg); 20229f7d47b0SAlexander V. Chernikov } 20239f7d47b0SAlexander V. Chernikov 202468394ec8SAlexander V. Chernikov static void 202568394ec8SAlexander V. Chernikov ta_foreach_ifidx(void *ta_state, struct table_info *ti, ta_foreach_f *f, 202668394ec8SAlexander V. Chernikov void *arg) 202768394ec8SAlexander V. Chernikov { 202868394ec8SAlexander V. Chernikov struct iftable_cfg *icfg; 202968394ec8SAlexander V. Chernikov struct wa_ifidx wa; 203068394ec8SAlexander V. Chernikov 203168394ec8SAlexander V. Chernikov icfg = (struct iftable_cfg *)ta_state; 203268394ec8SAlexander V. Chernikov 203368394ec8SAlexander V. Chernikov wa.f = f; 203468394ec8SAlexander V. Chernikov wa.arg = arg; 203568394ec8SAlexander V. Chernikov 203668394ec8SAlexander V. Chernikov ipfw_objhash_foreach(icfg->ii, foreach_ifidx, &wa); 203768394ec8SAlexander V. Chernikov } 203868394ec8SAlexander V. Chernikov 203974b941f0SAlexander V. Chernikov struct table_algo iface_idx = { 2040adea6201SAlexander V. Chernikov .name = "iface:array", 20419d099b4fSAlexander V. Chernikov .type = IPFW_TABLE_INTERFACE, 204257a1cf95SAlexander V. Chernikov .flags = TA_FLAG_DEFAULT, 204357a1cf95SAlexander V. Chernikov .ta_buf_size = sizeof(struct ta_buf_ifidx), 204468394ec8SAlexander V. Chernikov .init = ta_init_ifidx, 204568394ec8SAlexander V. Chernikov .destroy = ta_destroy_ifidx, 204668394ec8SAlexander V. Chernikov .prepare_add = ta_prepare_add_ifidx, 204768394ec8SAlexander V. Chernikov .prepare_del = ta_prepare_del_ifidx, 204868394ec8SAlexander V. Chernikov .add = ta_add_ifidx, 204968394ec8SAlexander V. Chernikov .del = ta_del_ifidx, 205068394ec8SAlexander V. Chernikov .flush_entry = ta_flush_ifidx_entry, 205168394ec8SAlexander V. Chernikov .foreach = ta_foreach_ifidx, 205268394ec8SAlexander V. Chernikov .dump_tentry = ta_dump_ifidx_tentry, 205368394ec8SAlexander V. Chernikov .find_tentry = ta_find_ifidx_tentry, 205468394ec8SAlexander V. Chernikov .prepare_mod = ta_prepare_mod_ifidx, 205568394ec8SAlexander V. Chernikov .fill_mod = ta_fill_mod_ifidx, 205668394ec8SAlexander V. Chernikov .modify = ta_modify_ifidx, 205768394ec8SAlexander V. Chernikov .flush_mod = ta_flush_mod_ifidx, 205868394ec8SAlexander V. Chernikov .change_ti = ta_change_ti_ifidx, 20599f7d47b0SAlexander V. Chernikov }; 20609f7d47b0SAlexander V. Chernikov 2061b23d5de9SAlexander V. Chernikov /* 2062b23d5de9SAlexander V. Chernikov * Number array cmds. 2063b23d5de9SAlexander V. Chernikov * 2064b23d5de9SAlexander V. Chernikov * Implementation: 2065b23d5de9SAlexander V. Chernikov * 2066b23d5de9SAlexander V. Chernikov * Runtime part: 2067b23d5de9SAlexander V. Chernikov * - sorted array of "struct numarray" pointed by ti->state. 2068b23d5de9SAlexander V. Chernikov * Array is allocated with rounding up to NUMARRAY_CHUNK. 2069b23d5de9SAlexander V. Chernikov * - current array size is stored in ti->data 2070b23d5de9SAlexander V. Chernikov * 2071b23d5de9SAlexander V. Chernikov */ 2072b23d5de9SAlexander V. Chernikov 2073b23d5de9SAlexander V. Chernikov struct numarray { 2074b23d5de9SAlexander V. Chernikov uint32_t number; 2075b23d5de9SAlexander V. Chernikov uint32_t value; 2076b23d5de9SAlexander V. Chernikov }; 2077b23d5de9SAlexander V. Chernikov 2078b23d5de9SAlexander V. Chernikov struct numarray_cfg { 2079b23d5de9SAlexander V. Chernikov void *main_ptr; 2080b23d5de9SAlexander V. Chernikov size_t size; /* Number of items allocated in array */ 2081b23d5de9SAlexander V. Chernikov size_t used; /* Number of items _active_ now */ 2082b23d5de9SAlexander V. Chernikov }; 2083b23d5de9SAlexander V. Chernikov 2084b23d5de9SAlexander V. Chernikov #define NUMARRAY_CHUNK 16 2085b23d5de9SAlexander V. Chernikov 2086b23d5de9SAlexander V. Chernikov int compare_numarray(const void *k, const void *v); 2087b23d5de9SAlexander V. Chernikov 2088b23d5de9SAlexander V. Chernikov int 2089b23d5de9SAlexander V. Chernikov compare_numarray(const void *k, const void *v) 2090b23d5de9SAlexander V. Chernikov { 2091b23d5de9SAlexander V. Chernikov struct numarray *na; 2092b23d5de9SAlexander V. Chernikov uint32_t key; 2093b23d5de9SAlexander V. Chernikov 2094b23d5de9SAlexander V. Chernikov key = *((uint32_t *)k); 2095b23d5de9SAlexander V. Chernikov na = (struct numarray *)v; 2096b23d5de9SAlexander V. Chernikov 2097b23d5de9SAlexander V. Chernikov if (key < na->number) 2098b23d5de9SAlexander V. Chernikov return (-1); 2099b23d5de9SAlexander V. Chernikov else if (key > na->number) 2100b23d5de9SAlexander V. Chernikov return (1); 2101b23d5de9SAlexander V. Chernikov 2102b23d5de9SAlexander V. Chernikov return (0); 2103b23d5de9SAlexander V. Chernikov } 2104b23d5de9SAlexander V. Chernikov 2105b23d5de9SAlexander V. Chernikov static struct numarray * 2106b23d5de9SAlexander V. Chernikov numarray_find(struct table_info *ti, void *key) 2107b23d5de9SAlexander V. Chernikov { 2108b23d5de9SAlexander V. Chernikov struct numarray *ri; 2109b23d5de9SAlexander V. Chernikov 2110b23d5de9SAlexander V. Chernikov ri = bsearch(key, ti->state, ti->data, sizeof(struct numarray), 2111b23d5de9SAlexander V. Chernikov compare_ifidx); 2112b23d5de9SAlexander V. Chernikov 2113b23d5de9SAlexander V. Chernikov return (ri); 2114b23d5de9SAlexander V. Chernikov } 2115b23d5de9SAlexander V. Chernikov 2116b23d5de9SAlexander V. Chernikov static int 2117b23d5de9SAlexander V. Chernikov ta_lookup_numarray(struct table_info *ti, void *key, uint32_t keylen, 2118b23d5de9SAlexander V. Chernikov uint32_t *val) 2119b23d5de9SAlexander V. Chernikov { 2120b23d5de9SAlexander V. Chernikov struct numarray *ri; 2121b23d5de9SAlexander V. Chernikov 2122b23d5de9SAlexander V. Chernikov ri = numarray_find(ti, key); 2123b23d5de9SAlexander V. Chernikov 2124b23d5de9SAlexander V. Chernikov if (ri != NULL) { 2125b23d5de9SAlexander V. Chernikov *val = ri->value; 2126b23d5de9SAlexander V. Chernikov return (1); 2127b23d5de9SAlexander V. Chernikov } 2128b23d5de9SAlexander V. Chernikov 2129b23d5de9SAlexander V. Chernikov return (0); 2130b23d5de9SAlexander V. Chernikov } 2131b23d5de9SAlexander V. Chernikov 2132b23d5de9SAlexander V. Chernikov static int 2133b23d5de9SAlexander V. Chernikov ta_init_numarray(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti, 2134914bffb6SAlexander V. Chernikov char *data, uint8_t tflags) 2135b23d5de9SAlexander V. Chernikov { 2136b23d5de9SAlexander V. Chernikov struct numarray_cfg *cfg; 2137b23d5de9SAlexander V. Chernikov 2138b23d5de9SAlexander V. Chernikov cfg = malloc(sizeof(*cfg), M_IPFW, M_WAITOK | M_ZERO); 2139b23d5de9SAlexander V. Chernikov 2140b23d5de9SAlexander V. Chernikov cfg->size = NUMARRAY_CHUNK; 2141b23d5de9SAlexander V. Chernikov cfg->main_ptr = malloc(sizeof(struct numarray) * cfg->size, M_IPFW, 2142b23d5de9SAlexander V. Chernikov M_WAITOK | M_ZERO); 2143b23d5de9SAlexander V. Chernikov 2144b23d5de9SAlexander V. Chernikov *ta_state = cfg; 2145b23d5de9SAlexander V. Chernikov ti->state = cfg->main_ptr; 2146b23d5de9SAlexander V. Chernikov ti->lookup = ta_lookup_numarray; 2147b23d5de9SAlexander V. Chernikov 2148b23d5de9SAlexander V. Chernikov return (0); 2149b23d5de9SAlexander V. Chernikov } 2150b23d5de9SAlexander V. Chernikov 2151b23d5de9SAlexander V. Chernikov /* 2152b23d5de9SAlexander V. Chernikov * Destroys table @ti 2153b23d5de9SAlexander V. Chernikov */ 2154b23d5de9SAlexander V. Chernikov static void 2155b23d5de9SAlexander V. Chernikov ta_destroy_numarray(void *ta_state, struct table_info *ti) 2156b23d5de9SAlexander V. Chernikov { 2157b23d5de9SAlexander V. Chernikov struct numarray_cfg *cfg; 2158b23d5de9SAlexander V. Chernikov 2159b23d5de9SAlexander V. Chernikov cfg = (struct numarray_cfg *)ta_state; 2160b23d5de9SAlexander V. Chernikov 2161b23d5de9SAlexander V. Chernikov if (cfg->main_ptr != NULL) 2162b23d5de9SAlexander V. Chernikov free(cfg->main_ptr, M_IPFW); 2163b23d5de9SAlexander V. Chernikov 2164b23d5de9SAlexander V. Chernikov free(cfg, M_IPFW); 2165b23d5de9SAlexander V. Chernikov } 2166b23d5de9SAlexander V. Chernikov 2167b23d5de9SAlexander V. Chernikov struct ta_buf_numarray 2168b23d5de9SAlexander V. Chernikov { 2169b23d5de9SAlexander V. Chernikov struct numarray na; 2170b23d5de9SAlexander V. Chernikov }; 2171b23d5de9SAlexander V. Chernikov 2172b23d5de9SAlexander V. Chernikov /* 2173b23d5de9SAlexander V. Chernikov * Prepare for addition/deletion to an array. 2174b23d5de9SAlexander V. Chernikov */ 2175b23d5de9SAlexander V. Chernikov static int 2176b23d5de9SAlexander V. Chernikov ta_prepare_add_numarray(struct ip_fw_chain *ch, struct tentry_info *tei, 2177b23d5de9SAlexander V. Chernikov void *ta_buf) 2178b23d5de9SAlexander V. Chernikov { 2179b23d5de9SAlexander V. Chernikov struct ta_buf_numarray *tb; 2180b23d5de9SAlexander V. Chernikov 2181b23d5de9SAlexander V. Chernikov tb = (struct ta_buf_numarray *)ta_buf; 2182b23d5de9SAlexander V. Chernikov memset(tb, 0, sizeof(*tb)); 2183b23d5de9SAlexander V. Chernikov 2184b23d5de9SAlexander V. Chernikov tb->na.number = *((uint32_t *)tei->paddr); 2185b23d5de9SAlexander V. Chernikov tb->na.value = tei->value; 2186b23d5de9SAlexander V. Chernikov 2187b23d5de9SAlexander V. Chernikov return (0); 2188b23d5de9SAlexander V. Chernikov } 2189b23d5de9SAlexander V. Chernikov 2190b23d5de9SAlexander V. Chernikov static int 2191b23d5de9SAlexander V. Chernikov ta_add_numarray(void *ta_state, struct table_info *ti, struct tentry_info *tei, 2192b23d5de9SAlexander V. Chernikov void *ta_buf, uint64_t *pflags, uint32_t *pnum) 2193b23d5de9SAlexander V. Chernikov { 2194b23d5de9SAlexander V. Chernikov struct numarray_cfg *cfg; 2195b23d5de9SAlexander V. Chernikov struct ta_buf_numarray *tb; 2196b23d5de9SAlexander V. Chernikov struct numarray *ri; 2197b23d5de9SAlexander V. Chernikov int res; 2198b23d5de9SAlexander V. Chernikov 2199b23d5de9SAlexander V. Chernikov tb = (struct ta_buf_numarray*)ta_buf; 2200b23d5de9SAlexander V. Chernikov cfg = (struct numarray_cfg *)ta_state; 2201b23d5de9SAlexander V. Chernikov 2202b23d5de9SAlexander V. Chernikov ri = numarray_find(ti, &tb->na.number); 2203b23d5de9SAlexander V. Chernikov 2204b23d5de9SAlexander V. Chernikov if (ri != NULL) { 2205b23d5de9SAlexander V. Chernikov if ((tei->flags & TEI_FLAGS_UPDATE) == 0) 2206b23d5de9SAlexander V. Chernikov return (EEXIST); 2207b23d5de9SAlexander V. Chernikov 2208b23d5de9SAlexander V. Chernikov /* We need to update value */ 2209b23d5de9SAlexander V. Chernikov ri->value = tb->na.value; 2210b23d5de9SAlexander V. Chernikov /* Indicate that update has happened instead of addition */ 2211b23d5de9SAlexander V. Chernikov tei->flags |= TEI_FLAGS_UPDATED; 2212b23d5de9SAlexander V. Chernikov *pnum = 0; 2213b23d5de9SAlexander V. Chernikov return (0); 2214b23d5de9SAlexander V. Chernikov } 2215b23d5de9SAlexander V. Chernikov 2216b23d5de9SAlexander V. Chernikov res = badd(&tb->na.number, &tb->na, cfg->main_ptr, cfg->used, 2217b23d5de9SAlexander V. Chernikov sizeof(struct numarray), compare_numarray); 2218b23d5de9SAlexander V. Chernikov 2219b23d5de9SAlexander V. Chernikov KASSERT(res == 1, ("number %d already exists", tb->na.number)); 2220b23d5de9SAlexander V. Chernikov cfg->used++; 2221b23d5de9SAlexander V. Chernikov ti->data = cfg->used; 2222b23d5de9SAlexander V. Chernikov 2223b23d5de9SAlexander V. Chernikov if (cfg->used + 1 == cfg->size) { 2224b23d5de9SAlexander V. Chernikov /* Notify core we need to grow */ 2225b23d5de9SAlexander V. Chernikov *pflags = cfg->size + NUMARRAY_CHUNK; 2226b23d5de9SAlexander V. Chernikov } 2227b23d5de9SAlexander V. Chernikov *pnum = 1; 2228b23d5de9SAlexander V. Chernikov 2229b23d5de9SAlexander V. Chernikov return (0); 2230b23d5de9SAlexander V. Chernikov } 2231b23d5de9SAlexander V. Chernikov 2232b23d5de9SAlexander V. Chernikov /* 2233b23d5de9SAlexander V. Chernikov * Remove key from both configuration list and 2234b23d5de9SAlexander V. Chernikov * runtime array. Removed interface notification. 2235b23d5de9SAlexander V. Chernikov */ 2236b23d5de9SAlexander V. Chernikov static int 2237b23d5de9SAlexander V. Chernikov ta_del_numarray(void *ta_state, struct table_info *ti, struct tentry_info *tei, 2238b23d5de9SAlexander V. Chernikov void *ta_buf, uint64_t *pflags, uint32_t *pnum) 2239b23d5de9SAlexander V. Chernikov { 2240b23d5de9SAlexander V. Chernikov struct numarray_cfg *cfg; 2241b23d5de9SAlexander V. Chernikov struct ta_buf_numarray *tb; 2242b23d5de9SAlexander V. Chernikov struct numarray *ri; 2243b23d5de9SAlexander V. Chernikov int res; 2244b23d5de9SAlexander V. Chernikov 2245b23d5de9SAlexander V. Chernikov tb = (struct ta_buf_numarray *)ta_buf; 2246b23d5de9SAlexander V. Chernikov cfg = (struct numarray_cfg *)ta_state; 2247b23d5de9SAlexander V. Chernikov 2248b23d5de9SAlexander V. Chernikov ri = numarray_find(ti, &tb->na.number); 2249b23d5de9SAlexander V. Chernikov if (ri == NULL) 2250b23d5de9SAlexander V. Chernikov return (ENOENT); 2251b23d5de9SAlexander V. Chernikov 2252b23d5de9SAlexander V. Chernikov res = bdel(&tb->na.number, cfg->main_ptr, cfg->used, 2253b23d5de9SAlexander V. Chernikov sizeof(struct numarray), compare_numarray); 2254b23d5de9SAlexander V. Chernikov 2255b23d5de9SAlexander V. Chernikov KASSERT(res == 1, ("number %u does not exist", tb->na.number)); 2256b23d5de9SAlexander V. Chernikov cfg->used--; 2257b23d5de9SAlexander V. Chernikov ti->data = cfg->used; 2258b23d5de9SAlexander V. Chernikov 2259b23d5de9SAlexander V. Chernikov *pnum = 1; 2260b23d5de9SAlexander V. Chernikov 2261b23d5de9SAlexander V. Chernikov return (0); 2262b23d5de9SAlexander V. Chernikov } 2263b23d5de9SAlexander V. Chernikov 2264b23d5de9SAlexander V. Chernikov static void 2265b23d5de9SAlexander V. Chernikov ta_flush_numarray_entry(struct ip_fw_chain *ch, struct tentry_info *tei, 2266b23d5de9SAlexander V. Chernikov void *ta_buf) 2267b23d5de9SAlexander V. Chernikov { 2268b23d5de9SAlexander V. Chernikov 2269b23d5de9SAlexander V. Chernikov /* Do nothing */ 2270b23d5de9SAlexander V. Chernikov } 2271b23d5de9SAlexander V. Chernikov 2272b23d5de9SAlexander V. Chernikov 2273b23d5de9SAlexander V. Chernikov /* 2274b23d5de9SAlexander V. Chernikov * Table growing callbacks. 2275b23d5de9SAlexander V. Chernikov */ 2276b23d5de9SAlexander V. Chernikov 2277b23d5de9SAlexander V. Chernikov /* 2278b23d5de9SAlexander V. Chernikov * Allocate ned, larger runtime numarray array. 2279b23d5de9SAlexander V. Chernikov */ 2280b23d5de9SAlexander V. Chernikov static int 2281b23d5de9SAlexander V. Chernikov ta_prepare_mod_numarray(void *ta_buf, uint64_t *pflags) 2282b23d5de9SAlexander V. Chernikov { 2283b23d5de9SAlexander V. Chernikov struct mod_item *mi; 2284b23d5de9SAlexander V. Chernikov 2285b23d5de9SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 2286b23d5de9SAlexander V. Chernikov 2287b23d5de9SAlexander V. Chernikov memset(mi, 0, sizeof(struct mod_item)); 2288b23d5de9SAlexander V. Chernikov mi->size = *pflags; 2289b23d5de9SAlexander V. Chernikov mi->main_ptr = malloc(sizeof(struct numarray) * mi->size, M_IPFW, 2290b23d5de9SAlexander V. Chernikov M_WAITOK | M_ZERO); 2291b23d5de9SAlexander V. Chernikov 2292b23d5de9SAlexander V. Chernikov return (0); 2293b23d5de9SAlexander V. Chernikov } 2294b23d5de9SAlexander V. Chernikov 2295b23d5de9SAlexander V. Chernikov /* 2296b23d5de9SAlexander V. Chernikov * Copy data from old runtime array to new one. 2297b23d5de9SAlexander V. Chernikov */ 2298b23d5de9SAlexander V. Chernikov static int 2299b23d5de9SAlexander V. Chernikov ta_fill_mod_numarray(void *ta_state, struct table_info *ti, void *ta_buf, 2300b23d5de9SAlexander V. Chernikov uint64_t *pflags) 2301b23d5de9SAlexander V. Chernikov { 2302b23d5de9SAlexander V. Chernikov struct mod_item *mi; 2303b23d5de9SAlexander V. Chernikov struct numarray_cfg *cfg; 2304b23d5de9SAlexander V. Chernikov 2305b23d5de9SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 2306b23d5de9SAlexander V. Chernikov cfg = (struct numarray_cfg *)ta_state; 2307b23d5de9SAlexander V. Chernikov 2308b23d5de9SAlexander V. Chernikov /* Check if we still need to grow array */ 2309b23d5de9SAlexander V. Chernikov if (cfg->size >= mi->size) { 2310b23d5de9SAlexander V. Chernikov *pflags = 0; 2311b23d5de9SAlexander V. Chernikov return (0); 2312b23d5de9SAlexander V. Chernikov } 2313b23d5de9SAlexander V. Chernikov 2314b23d5de9SAlexander V. Chernikov memcpy(mi->main_ptr, cfg->main_ptr, cfg->used * sizeof(struct numarray)); 2315b23d5de9SAlexander V. Chernikov 2316b23d5de9SAlexander V. Chernikov return (0); 2317b23d5de9SAlexander V. Chernikov } 2318b23d5de9SAlexander V. Chernikov 2319b23d5de9SAlexander V. Chernikov /* 2320b23d5de9SAlexander V. Chernikov * Switch old & new arrays. 2321b23d5de9SAlexander V. Chernikov */ 2322b23d5de9SAlexander V. Chernikov static int 2323b23d5de9SAlexander V. Chernikov ta_modify_numarray(void *ta_state, struct table_info *ti, void *ta_buf, 2324b23d5de9SAlexander V. Chernikov uint64_t pflags) 2325b23d5de9SAlexander V. Chernikov { 2326b23d5de9SAlexander V. Chernikov struct mod_item *mi; 2327b23d5de9SAlexander V. Chernikov struct numarray_cfg *cfg; 2328b23d5de9SAlexander V. Chernikov void *old_ptr; 2329b23d5de9SAlexander V. Chernikov 2330b23d5de9SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 2331b23d5de9SAlexander V. Chernikov cfg = (struct numarray_cfg *)ta_state; 2332b23d5de9SAlexander V. Chernikov 2333b23d5de9SAlexander V. Chernikov old_ptr = cfg->main_ptr; 2334b23d5de9SAlexander V. Chernikov cfg->main_ptr = mi->main_ptr; 2335b23d5de9SAlexander V. Chernikov cfg->size = mi->size; 2336b23d5de9SAlexander V. Chernikov ti->state = cfg->main_ptr; 2337b23d5de9SAlexander V. Chernikov 2338b23d5de9SAlexander V. Chernikov mi->main_ptr = old_ptr; 2339b23d5de9SAlexander V. Chernikov 2340b23d5de9SAlexander V. Chernikov return (0); 2341b23d5de9SAlexander V. Chernikov } 2342b23d5de9SAlexander V. Chernikov 2343b23d5de9SAlexander V. Chernikov /* 2344b23d5de9SAlexander V. Chernikov * Free unneded array. 2345b23d5de9SAlexander V. Chernikov */ 2346b23d5de9SAlexander V. Chernikov static void 2347b23d5de9SAlexander V. Chernikov ta_flush_mod_numarray(void *ta_buf) 2348b23d5de9SAlexander V. Chernikov { 2349b23d5de9SAlexander V. Chernikov struct mod_item *mi; 2350b23d5de9SAlexander V. Chernikov 2351b23d5de9SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 2352b23d5de9SAlexander V. Chernikov if (mi->main_ptr != NULL) 2353b23d5de9SAlexander V. Chernikov free(mi->main_ptr, M_IPFW); 2354b23d5de9SAlexander V. Chernikov } 2355b23d5de9SAlexander V. Chernikov 2356b23d5de9SAlexander V. Chernikov static int 2357b23d5de9SAlexander V. Chernikov ta_dump_numarray_tentry(void *ta_state, struct table_info *ti, void *e, 2358b23d5de9SAlexander V. Chernikov ipfw_obj_tentry *tent) 2359b23d5de9SAlexander V. Chernikov { 2360b23d5de9SAlexander V. Chernikov struct numarray *na; 2361b23d5de9SAlexander V. Chernikov 2362b23d5de9SAlexander V. Chernikov na = (struct numarray *)e; 2363b23d5de9SAlexander V. Chernikov 2364b23d5de9SAlexander V. Chernikov tent->k.key = na->number; 2365b23d5de9SAlexander V. Chernikov tent->value = na->value; 2366b23d5de9SAlexander V. Chernikov 2367b23d5de9SAlexander V. Chernikov return (0); 2368b23d5de9SAlexander V. Chernikov } 2369b23d5de9SAlexander V. Chernikov 2370b23d5de9SAlexander V. Chernikov static int 2371914bffb6SAlexander V. Chernikov ta_find_numarray_tentry(void *ta_state, struct table_info *ti, 2372914bffb6SAlexander V. Chernikov ipfw_obj_tentry *tent) 2373b23d5de9SAlexander V. Chernikov { 2374b23d5de9SAlexander V. Chernikov struct numarray_cfg *cfg; 2375b23d5de9SAlexander V. Chernikov struct numarray *ri; 2376b23d5de9SAlexander V. Chernikov 2377b23d5de9SAlexander V. Chernikov cfg = (struct numarray_cfg *)ta_state; 2378b23d5de9SAlexander V. Chernikov 2379914bffb6SAlexander V. Chernikov ri = numarray_find(ti, &tent->k.key); 2380b23d5de9SAlexander V. Chernikov 2381b23d5de9SAlexander V. Chernikov if (ri != NULL) { 2382b23d5de9SAlexander V. Chernikov ta_dump_numarray_tentry(ta_state, ti, ri, tent); 2383b23d5de9SAlexander V. Chernikov return (0); 2384b23d5de9SAlexander V. Chernikov } 2385b23d5de9SAlexander V. Chernikov 2386b23d5de9SAlexander V. Chernikov return (ENOENT); 2387b23d5de9SAlexander V. Chernikov } 2388b23d5de9SAlexander V. Chernikov 2389b23d5de9SAlexander V. Chernikov static void 2390b23d5de9SAlexander V. Chernikov ta_foreach_numarray(void *ta_state, struct table_info *ti, ta_foreach_f *f, 2391b23d5de9SAlexander V. Chernikov void *arg) 2392b23d5de9SAlexander V. Chernikov { 2393b23d5de9SAlexander V. Chernikov struct numarray_cfg *cfg; 2394b23d5de9SAlexander V. Chernikov struct numarray *array; 2395b23d5de9SAlexander V. Chernikov int i; 2396b23d5de9SAlexander V. Chernikov 2397b23d5de9SAlexander V. Chernikov cfg = (struct numarray_cfg *)ta_state; 2398b23d5de9SAlexander V. Chernikov array = cfg->main_ptr; 2399b23d5de9SAlexander V. Chernikov 2400b23d5de9SAlexander V. Chernikov for (i = 0; i < cfg->used; i++) 2401b23d5de9SAlexander V. Chernikov f(&array[i], arg); 2402b23d5de9SAlexander V. Chernikov } 2403b23d5de9SAlexander V. Chernikov 2404b23d5de9SAlexander V. Chernikov struct table_algo number_array = { 2405b23d5de9SAlexander V. Chernikov .name = "number:array", 2406b23d5de9SAlexander V. Chernikov .type = IPFW_TABLE_NUMBER, 240757a1cf95SAlexander V. Chernikov .ta_buf_size = sizeof(struct ta_buf_numarray), 2408b23d5de9SAlexander V. Chernikov .init = ta_init_numarray, 2409b23d5de9SAlexander V. Chernikov .destroy = ta_destroy_numarray, 2410b23d5de9SAlexander V. Chernikov .prepare_add = ta_prepare_add_numarray, 2411b23d5de9SAlexander V. Chernikov .prepare_del = ta_prepare_add_numarray, 2412b23d5de9SAlexander V. Chernikov .add = ta_add_numarray, 2413b23d5de9SAlexander V. Chernikov .del = ta_del_numarray, 2414b23d5de9SAlexander V. Chernikov .flush_entry = ta_flush_numarray_entry, 2415b23d5de9SAlexander V. Chernikov .foreach = ta_foreach_numarray, 2416b23d5de9SAlexander V. Chernikov .dump_tentry = ta_dump_numarray_tentry, 2417b23d5de9SAlexander V. Chernikov .find_tentry = ta_find_numarray_tentry, 2418b23d5de9SAlexander V. Chernikov .prepare_mod = ta_prepare_mod_numarray, 2419b23d5de9SAlexander V. Chernikov .fill_mod = ta_fill_mod_numarray, 2420b23d5de9SAlexander V. Chernikov .modify = ta_modify_numarray, 2421b23d5de9SAlexander V. Chernikov .flush_mod = ta_flush_mod_numarray, 2422b23d5de9SAlexander V. Chernikov }; 2423b23d5de9SAlexander V. Chernikov 2424914bffb6SAlexander V. Chernikov /* 2425914bffb6SAlexander V. Chernikov * flow:hash cmds 2426914bffb6SAlexander V. Chernikov * 2427914bffb6SAlexander V. Chernikov * 2428914bffb6SAlexander V. Chernikov * ti->data: 2429914bffb6SAlexander V. Chernikov * [inv.mask4][inv.mask6][log2hsize4][log2hsize6] 2430914bffb6SAlexander V. Chernikov * [ 8][ 8[ 8][ 8] 2431914bffb6SAlexander V. Chernikov * 2432914bffb6SAlexander V. Chernikov * inv.mask4: 32 - mask 2433914bffb6SAlexander V. Chernikov * inv.mask6: 2434914bffb6SAlexander V. Chernikov * 1) _slow lookup: mask 2435914bffb6SAlexander V. Chernikov * 2) _aligned: (128 - mask) / 8 2436914bffb6SAlexander V. Chernikov * 3) _64: 8 2437914bffb6SAlexander V. Chernikov * 2438914bffb6SAlexander V. Chernikov * 2439914bffb6SAlexander V. Chernikov * pflags: 2440914bffb6SAlexander V. Chernikov * [v4=1/v6=0][hsize] 2441914bffb6SAlexander V. Chernikov * [ 32][ 32] 2442914bffb6SAlexander V. Chernikov */ 2443914bffb6SAlexander V. Chernikov 2444914bffb6SAlexander V. Chernikov struct fhashentry; 2445914bffb6SAlexander V. Chernikov 2446914bffb6SAlexander V. Chernikov SLIST_HEAD(fhashbhead, fhashentry); 2447914bffb6SAlexander V. Chernikov 2448914bffb6SAlexander V. Chernikov /* 2449914bffb6SAlexander V. Chernikov struct tflow_entry { 2450914bffb6SAlexander V. Chernikov uint8_t af; 2451914bffb6SAlexander V. Chernikov uint8_t proto; 2452914bffb6SAlexander V. Chernikov uint16_t spare; 2453914bffb6SAlexander V. Chernikov uint16_t dport; 2454914bffb6SAlexander V. Chernikov uint16_t sport; 2455914bffb6SAlexander V. Chernikov union { 2456914bffb6SAlexander V. Chernikov struct { 2457914bffb6SAlexander V. Chernikov struct in_addr sip; 2458914bffb6SAlexander V. Chernikov struct in_addr dip; 2459914bffb6SAlexander V. Chernikov } v4; 2460914bffb6SAlexander V. Chernikov struct { 2461914bffb6SAlexander V. Chernikov struct in6_addr sip6; 2462914bffb6SAlexander V. Chernikov struct in6_addr dip6; 2463914bffb6SAlexander V. Chernikov } v6; 2464914bffb6SAlexander V. Chernikov } a; 2465914bffb6SAlexander V. Chernikov }; 2466914bffb6SAlexander V. Chernikov */ 2467914bffb6SAlexander V. Chernikov 2468914bffb6SAlexander V. Chernikov struct fhashentry { 2469914bffb6SAlexander V. Chernikov SLIST_ENTRY(fhashentry) next; 2470914bffb6SAlexander V. Chernikov uint8_t af; 2471914bffb6SAlexander V. Chernikov uint8_t proto; 2472914bffb6SAlexander V. Chernikov uint16_t spare0; 2473914bffb6SAlexander V. Chernikov uint16_t dport; 2474914bffb6SAlexander V. Chernikov uint16_t sport; 2475914bffb6SAlexander V. Chernikov uint32_t value; 2476914bffb6SAlexander V. Chernikov uint32_t spare1; 2477914bffb6SAlexander V. Chernikov }; 2478914bffb6SAlexander V. Chernikov 2479914bffb6SAlexander V. Chernikov struct fhashentry4 { 2480914bffb6SAlexander V. Chernikov struct fhashentry e; 2481914bffb6SAlexander V. Chernikov struct in_addr dip; 2482914bffb6SAlexander V. Chernikov struct in_addr sip; 2483914bffb6SAlexander V. Chernikov }; 2484914bffb6SAlexander V. Chernikov 2485914bffb6SAlexander V. Chernikov struct fhashentry6 { 2486914bffb6SAlexander V. Chernikov struct fhashentry e; 2487914bffb6SAlexander V. Chernikov struct in6_addr dip6; 2488914bffb6SAlexander V. Chernikov struct in6_addr sip6; 2489914bffb6SAlexander V. Chernikov }; 2490914bffb6SAlexander V. Chernikov 2491914bffb6SAlexander V. Chernikov struct fhash_cfg { 2492914bffb6SAlexander V. Chernikov struct fhashbhead *head; 2493914bffb6SAlexander V. Chernikov size_t size; 2494914bffb6SAlexander V. Chernikov size_t items; 2495914bffb6SAlexander V. Chernikov struct fhashentry4 fe4; 2496914bffb6SAlexander V. Chernikov struct fhashentry6 fe6; 2497914bffb6SAlexander V. Chernikov }; 2498914bffb6SAlexander V. Chernikov 2499914bffb6SAlexander V. Chernikov static __inline int 2500914bffb6SAlexander V. Chernikov cmp_flow_ent(struct fhashentry *a, struct fhashentry *b, size_t sz) 2501914bffb6SAlexander V. Chernikov { 2502914bffb6SAlexander V. Chernikov uint64_t *ka, *kb; 2503914bffb6SAlexander V. Chernikov 2504914bffb6SAlexander V. Chernikov ka = (uint64_t *)(&a->next + 1); 2505914bffb6SAlexander V. Chernikov kb = (uint64_t *)(&b->next + 1); 2506914bffb6SAlexander V. Chernikov 2507914bffb6SAlexander V. Chernikov if (*ka == *kb && (memcmp(a + 1, b + 1, sz) == 0)) 2508914bffb6SAlexander V. Chernikov return (1); 2509914bffb6SAlexander V. Chernikov 2510914bffb6SAlexander V. Chernikov return (0); 2511914bffb6SAlexander V. Chernikov } 2512914bffb6SAlexander V. Chernikov 2513914bffb6SAlexander V. Chernikov static __inline uint32_t 2514914bffb6SAlexander V. Chernikov hash_flow4(struct fhashentry4 *f, int hsize) 2515914bffb6SAlexander V. Chernikov { 2516914bffb6SAlexander V. Chernikov uint32_t i; 2517914bffb6SAlexander V. Chernikov 2518914bffb6SAlexander V. Chernikov i = (f->dip.s_addr) ^ (f->sip.s_addr) ^ (f->e.dport) ^ (f->e.sport); 2519914bffb6SAlexander V. Chernikov 2520914bffb6SAlexander V. Chernikov return (i % (hsize - 1)); 2521914bffb6SAlexander V. Chernikov } 2522914bffb6SAlexander V. Chernikov 2523914bffb6SAlexander V. Chernikov static __inline uint32_t 2524914bffb6SAlexander V. Chernikov hash_flow6(struct fhashentry6 *f, int hsize) 2525914bffb6SAlexander V. Chernikov { 2526914bffb6SAlexander V. Chernikov uint32_t i; 2527914bffb6SAlexander V. Chernikov 2528914bffb6SAlexander V. Chernikov i = (f->dip6.__u6_addr.__u6_addr32[2]) ^ 2529914bffb6SAlexander V. Chernikov (f->dip6.__u6_addr.__u6_addr32[3]) ^ 2530914bffb6SAlexander V. Chernikov (f->sip6.__u6_addr.__u6_addr32[2]) ^ 2531914bffb6SAlexander V. Chernikov (f->sip6.__u6_addr.__u6_addr32[3]) ^ 2532914bffb6SAlexander V. Chernikov (f->e.dport) ^ (f->e.sport); 2533914bffb6SAlexander V. Chernikov 2534914bffb6SAlexander V. Chernikov return (i % (hsize - 1)); 2535914bffb6SAlexander V. Chernikov } 2536914bffb6SAlexander V. Chernikov 2537914bffb6SAlexander V. Chernikov static uint32_t 2538914bffb6SAlexander V. Chernikov hash_flow_ent(struct fhashentry *ent, uint32_t size) 2539914bffb6SAlexander V. Chernikov { 2540914bffb6SAlexander V. Chernikov uint32_t hash; 2541914bffb6SAlexander V. Chernikov 2542914bffb6SAlexander V. Chernikov if (ent->af == AF_INET) { 2543914bffb6SAlexander V. Chernikov hash = hash_flow4((struct fhashentry4 *)ent, size); 2544914bffb6SAlexander V. Chernikov } else { 2545914bffb6SAlexander V. Chernikov hash = hash_flow6((struct fhashentry6 *)ent, size); 2546914bffb6SAlexander V. Chernikov } 2547914bffb6SAlexander V. Chernikov 2548914bffb6SAlexander V. Chernikov return (hash); 2549914bffb6SAlexander V. Chernikov } 2550914bffb6SAlexander V. Chernikov 2551914bffb6SAlexander V. Chernikov static int 2552914bffb6SAlexander V. Chernikov ta_lookup_fhash(struct table_info *ti, void *key, uint32_t keylen, 2553914bffb6SAlexander V. Chernikov uint32_t *val) 2554914bffb6SAlexander V. Chernikov { 2555914bffb6SAlexander V. Chernikov struct fhashbhead *head; 2556914bffb6SAlexander V. Chernikov struct fhashentry *ent; 2557914bffb6SAlexander V. Chernikov struct fhashentry4 *m4; 2558914bffb6SAlexander V. Chernikov struct ipfw_flow_id *id; 2559914bffb6SAlexander V. Chernikov uint16_t hash, hsize; 2560914bffb6SAlexander V. Chernikov 2561914bffb6SAlexander V. Chernikov id = (struct ipfw_flow_id *)key; 2562914bffb6SAlexander V. Chernikov head = (struct fhashbhead *)ti->state; 2563914bffb6SAlexander V. Chernikov hsize = ti->data; 2564914bffb6SAlexander V. Chernikov m4 = (struct fhashentry4 *)ti->xstate; 2565914bffb6SAlexander V. Chernikov 2566914bffb6SAlexander V. Chernikov if (id->addr_type == 4) { 2567914bffb6SAlexander V. Chernikov struct fhashentry4 f; 2568914bffb6SAlexander V. Chernikov 2569914bffb6SAlexander V. Chernikov /* Copy hash mask */ 2570914bffb6SAlexander V. Chernikov f = *m4; 2571914bffb6SAlexander V. Chernikov 2572914bffb6SAlexander V. Chernikov f.dip.s_addr &= id->dst_ip; 2573914bffb6SAlexander V. Chernikov f.sip.s_addr &= id->src_ip; 2574914bffb6SAlexander V. Chernikov f.e.dport &= id->dst_port; 2575914bffb6SAlexander V. Chernikov f.e.sport &= id->src_port; 2576914bffb6SAlexander V. Chernikov f.e.proto &= id->proto; 2577914bffb6SAlexander V. Chernikov hash = hash_flow4(&f, hsize); 2578914bffb6SAlexander V. Chernikov SLIST_FOREACH(ent, &head[hash], next) { 2579914bffb6SAlexander V. Chernikov if (cmp_flow_ent(ent, &f.e, 2 * 4) != 0) { 2580914bffb6SAlexander V. Chernikov *val = ent->value; 2581914bffb6SAlexander V. Chernikov return (1); 2582914bffb6SAlexander V. Chernikov } 2583914bffb6SAlexander V. Chernikov } 2584914bffb6SAlexander V. Chernikov } else if (id->addr_type == 6) { 2585914bffb6SAlexander V. Chernikov struct fhashentry6 f; 2586914bffb6SAlexander V. Chernikov uint64_t *fp, *idp; 2587914bffb6SAlexander V. Chernikov 2588914bffb6SAlexander V. Chernikov /* Copy hash mask */ 2589914bffb6SAlexander V. Chernikov f = *((struct fhashentry6 *)(m4 + 1)); 2590914bffb6SAlexander V. Chernikov 2591914bffb6SAlexander V. Chernikov /* Handle lack of __u6_addr.__u6_addr64 */ 2592914bffb6SAlexander V. Chernikov fp = (uint64_t *)&f.dip6; 2593914bffb6SAlexander V. Chernikov idp = (uint64_t *)&id->dst_ip6; 2594914bffb6SAlexander V. Chernikov /* src IPv6 is stored after dst IPv6 */ 2595914bffb6SAlexander V. Chernikov *fp++ &= *idp++; 2596914bffb6SAlexander V. Chernikov *fp++ &= *idp++; 2597914bffb6SAlexander V. Chernikov *fp++ &= *idp++; 2598914bffb6SAlexander V. Chernikov *fp &= *idp; 2599914bffb6SAlexander V. Chernikov f.e.dport &= id->dst_port; 2600914bffb6SAlexander V. Chernikov f.e.sport &= id->src_port; 2601914bffb6SAlexander V. Chernikov f.e.proto &= id->proto; 2602914bffb6SAlexander V. Chernikov hash = hash_flow6(&f, hsize); 2603914bffb6SAlexander V. Chernikov SLIST_FOREACH(ent, &head[hash], next) { 2604914bffb6SAlexander V. Chernikov if (cmp_flow_ent(ent, &f.e, 2 * 16) != 0) { 2605914bffb6SAlexander V. Chernikov *val = ent->value; 2606914bffb6SAlexander V. Chernikov return (1); 2607914bffb6SAlexander V. Chernikov } 2608914bffb6SAlexander V. Chernikov } 2609914bffb6SAlexander V. Chernikov } 2610914bffb6SAlexander V. Chernikov 2611914bffb6SAlexander V. Chernikov return (0); 2612914bffb6SAlexander V. Chernikov } 2613914bffb6SAlexander V. Chernikov 2614914bffb6SAlexander V. Chernikov /* 2615914bffb6SAlexander V. Chernikov * New table. 2616914bffb6SAlexander V. Chernikov */ 2617914bffb6SAlexander V. Chernikov static int 2618914bffb6SAlexander V. Chernikov ta_init_fhash(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti, 2619914bffb6SAlexander V. Chernikov char *data, uint8_t tflags) 2620914bffb6SAlexander V. Chernikov { 2621914bffb6SAlexander V. Chernikov int i; 2622914bffb6SAlexander V. Chernikov struct fhash_cfg *cfg; 2623914bffb6SAlexander V. Chernikov struct fhashentry4 *fe4; 2624914bffb6SAlexander V. Chernikov struct fhashentry6 *fe6; 2625914bffb6SAlexander V. Chernikov 2626914bffb6SAlexander V. Chernikov cfg = malloc(sizeof(struct fhash_cfg), M_IPFW, M_WAITOK | M_ZERO); 2627914bffb6SAlexander V. Chernikov 2628914bffb6SAlexander V. Chernikov cfg->size = 512; 2629914bffb6SAlexander V. Chernikov 2630914bffb6SAlexander V. Chernikov cfg->head = malloc(sizeof(struct fhashbhead) * cfg->size, M_IPFW, 2631914bffb6SAlexander V. Chernikov M_WAITOK | M_ZERO); 2632914bffb6SAlexander V. Chernikov for (i = 0; i < cfg->size; i++) 2633914bffb6SAlexander V. Chernikov SLIST_INIT(&cfg->head[i]); 2634914bffb6SAlexander V. Chernikov 2635914bffb6SAlexander V. Chernikov /* Fill in fe masks based on @tflags */ 2636914bffb6SAlexander V. Chernikov fe4 = &cfg->fe4; 2637914bffb6SAlexander V. Chernikov fe6 = &cfg->fe6; 2638914bffb6SAlexander V. Chernikov if (tflags & IPFW_TFFLAG_SRCIP) { 2639914bffb6SAlexander V. Chernikov memset(&fe4->sip, 0xFF, sizeof(fe4->sip)); 2640914bffb6SAlexander V. Chernikov memset(&fe6->sip6, 0xFF, sizeof(fe6->sip6)); 2641914bffb6SAlexander V. Chernikov } 2642914bffb6SAlexander V. Chernikov if (tflags & IPFW_TFFLAG_DSTIP) { 2643914bffb6SAlexander V. Chernikov memset(&fe4->dip, 0xFF, sizeof(fe4->dip)); 2644914bffb6SAlexander V. Chernikov memset(&fe6->dip6, 0xFF, sizeof(fe6->dip6)); 2645914bffb6SAlexander V. Chernikov } 2646914bffb6SAlexander V. Chernikov if (tflags & IPFW_TFFLAG_SRCPORT) { 2647914bffb6SAlexander V. Chernikov memset(&fe4->e.sport, 0xFF, sizeof(fe4->e.sport)); 2648914bffb6SAlexander V. Chernikov memset(&fe6->e.sport, 0xFF, sizeof(fe6->e.sport)); 2649914bffb6SAlexander V. Chernikov } 2650914bffb6SAlexander V. Chernikov if (tflags & IPFW_TFFLAG_DSTPORT) { 2651914bffb6SAlexander V. Chernikov memset(&fe4->e.dport, 0xFF, sizeof(fe4->e.dport)); 2652914bffb6SAlexander V. Chernikov memset(&fe6->e.dport, 0xFF, sizeof(fe6->e.dport)); 2653914bffb6SAlexander V. Chernikov } 2654914bffb6SAlexander V. Chernikov if (tflags & IPFW_TFFLAG_PROTO) { 2655914bffb6SAlexander V. Chernikov memset(&fe4->e.proto, 0xFF, sizeof(fe4->e.proto)); 2656914bffb6SAlexander V. Chernikov memset(&fe6->e.proto, 0xFF, sizeof(fe6->e.proto)); 2657914bffb6SAlexander V. Chernikov } 2658914bffb6SAlexander V. Chernikov 2659914bffb6SAlexander V. Chernikov fe4->e.af = AF_INET; 2660914bffb6SAlexander V. Chernikov fe6->e.af = AF_INET6; 2661914bffb6SAlexander V. Chernikov 2662914bffb6SAlexander V. Chernikov *ta_state = cfg; 2663914bffb6SAlexander V. Chernikov ti->state = cfg->head; 2664914bffb6SAlexander V. Chernikov ti->xstate = &cfg->fe4; 2665914bffb6SAlexander V. Chernikov ti->data = cfg->size; 2666914bffb6SAlexander V. Chernikov ti->lookup = ta_lookup_fhash; 2667914bffb6SAlexander V. Chernikov 2668914bffb6SAlexander V. Chernikov return (0); 2669914bffb6SAlexander V. Chernikov } 2670914bffb6SAlexander V. Chernikov 2671914bffb6SAlexander V. Chernikov static void 2672914bffb6SAlexander V. Chernikov ta_destroy_fhash(void *ta_state, struct table_info *ti) 2673914bffb6SAlexander V. Chernikov { 2674914bffb6SAlexander V. Chernikov struct fhash_cfg *cfg; 2675914bffb6SAlexander V. Chernikov struct fhashentry *ent, *ent_next; 2676914bffb6SAlexander V. Chernikov int i; 2677914bffb6SAlexander V. Chernikov 2678914bffb6SAlexander V. Chernikov cfg = (struct fhash_cfg *)ta_state; 2679914bffb6SAlexander V. Chernikov 2680914bffb6SAlexander V. Chernikov for (i = 0; i < cfg->size; i++) 2681914bffb6SAlexander V. Chernikov SLIST_FOREACH_SAFE(ent, &cfg->head[i], next, ent_next) 2682914bffb6SAlexander V. Chernikov free(ent, M_IPFW_TBL); 2683914bffb6SAlexander V. Chernikov 2684914bffb6SAlexander V. Chernikov free(cfg->head, M_IPFW); 2685914bffb6SAlexander V. Chernikov free(cfg, M_IPFW); 2686914bffb6SAlexander V. Chernikov } 2687914bffb6SAlexander V. Chernikov 2688914bffb6SAlexander V. Chernikov static int 2689914bffb6SAlexander V. Chernikov ta_dump_fhash_tentry(void *ta_state, struct table_info *ti, void *e, 2690914bffb6SAlexander V. Chernikov ipfw_obj_tentry *tent) 2691914bffb6SAlexander V. Chernikov { 2692914bffb6SAlexander V. Chernikov struct fhash_cfg *cfg; 2693914bffb6SAlexander V. Chernikov struct fhashentry *ent; 2694914bffb6SAlexander V. Chernikov struct fhashentry4 *fe4; 2695914bffb6SAlexander V. Chernikov struct fhashentry6 *fe6; 2696914bffb6SAlexander V. Chernikov struct tflow_entry *tfe; 2697914bffb6SAlexander V. Chernikov 2698914bffb6SAlexander V. Chernikov cfg = (struct fhash_cfg *)ta_state; 2699914bffb6SAlexander V. Chernikov ent = (struct fhashentry *)e; 2700914bffb6SAlexander V. Chernikov tfe = &tent->k.flow; 2701914bffb6SAlexander V. Chernikov 2702914bffb6SAlexander V. Chernikov tfe->af = ent->af; 2703914bffb6SAlexander V. Chernikov tfe->proto = ent->proto; 2704914bffb6SAlexander V. Chernikov tfe->dport = htons(ent->dport); 2705914bffb6SAlexander V. Chernikov tfe->sport = htons(ent->sport); 2706914bffb6SAlexander V. Chernikov tent->value = ent->value; 2707914bffb6SAlexander V. Chernikov tent->subtype = ent->af; 2708914bffb6SAlexander V. Chernikov 2709914bffb6SAlexander V. Chernikov if (ent->af == AF_INET) { 2710914bffb6SAlexander V. Chernikov fe4 = (struct fhashentry4 *)ent; 2711914bffb6SAlexander V. Chernikov tfe->a.a4.sip.s_addr = htonl(fe4->sip.s_addr); 2712914bffb6SAlexander V. Chernikov tfe->a.a4.dip.s_addr = htonl(fe4->dip.s_addr); 2713914bffb6SAlexander V. Chernikov tent->masklen = 32; 2714914bffb6SAlexander V. Chernikov #ifdef INET6 2715914bffb6SAlexander V. Chernikov } else { 2716914bffb6SAlexander V. Chernikov fe6 = (struct fhashentry6 *)ent; 2717914bffb6SAlexander V. Chernikov tfe->a.a6.sip6 = fe6->sip6; 2718914bffb6SAlexander V. Chernikov tfe->a.a6.dip6 = fe6->dip6; 2719914bffb6SAlexander V. Chernikov tent->masklen = 128; 2720914bffb6SAlexander V. Chernikov #endif 2721914bffb6SAlexander V. Chernikov } 2722914bffb6SAlexander V. Chernikov 2723914bffb6SAlexander V. Chernikov return (0); 2724914bffb6SAlexander V. Chernikov } 2725914bffb6SAlexander V. Chernikov 2726914bffb6SAlexander V. Chernikov static int 2727914bffb6SAlexander V. Chernikov tei_to_fhash_ent(struct tentry_info *tei, struct fhashentry *ent) 2728914bffb6SAlexander V. Chernikov { 2729914bffb6SAlexander V. Chernikov struct fhashentry4 *fe4; 2730914bffb6SAlexander V. Chernikov struct fhashentry6 *fe6; 2731914bffb6SAlexander V. Chernikov struct tflow_entry *tfe; 2732914bffb6SAlexander V. Chernikov 2733914bffb6SAlexander V. Chernikov tfe = (struct tflow_entry *)tei->paddr; 2734914bffb6SAlexander V. Chernikov 2735914bffb6SAlexander V. Chernikov ent->af = tei->subtype; 2736914bffb6SAlexander V. Chernikov ent->proto = tfe->proto; 2737914bffb6SAlexander V. Chernikov ent->value = tei->value; 2738914bffb6SAlexander V. Chernikov ent->dport = ntohs(tfe->dport); 2739914bffb6SAlexander V. Chernikov ent->sport = ntohs(tfe->sport); 2740914bffb6SAlexander V. Chernikov 2741914bffb6SAlexander V. Chernikov if (tei->subtype == AF_INET) { 2742914bffb6SAlexander V. Chernikov #ifdef INET 2743914bffb6SAlexander V. Chernikov fe4 = (struct fhashentry4 *)ent; 2744914bffb6SAlexander V. Chernikov fe4->sip.s_addr = ntohl(tfe->a.a4.sip.s_addr); 2745914bffb6SAlexander V. Chernikov fe4->dip.s_addr = ntohl(tfe->a.a4.dip.s_addr); 2746914bffb6SAlexander V. Chernikov #endif 2747914bffb6SAlexander V. Chernikov #ifdef INET6 2748914bffb6SAlexander V. Chernikov } else if (tei->subtype == AF_INET6) { 2749914bffb6SAlexander V. Chernikov fe6 = (struct fhashentry6 *)ent; 2750914bffb6SAlexander V. Chernikov fe6->sip6 = tfe->a.a6.sip6; 2751914bffb6SAlexander V. Chernikov fe6->dip6 = tfe->a.a6.dip6; 2752914bffb6SAlexander V. Chernikov #endif 2753914bffb6SAlexander V. Chernikov } else { 2754914bffb6SAlexander V. Chernikov /* Unknown CIDR type */ 2755914bffb6SAlexander V. Chernikov return (EINVAL); 2756914bffb6SAlexander V. Chernikov } 2757914bffb6SAlexander V. Chernikov 2758914bffb6SAlexander V. Chernikov return (0); 2759914bffb6SAlexander V. Chernikov } 2760914bffb6SAlexander V. Chernikov 2761914bffb6SAlexander V. Chernikov 2762914bffb6SAlexander V. Chernikov static int 2763914bffb6SAlexander V. Chernikov ta_find_fhash_tentry(void *ta_state, struct table_info *ti, 2764914bffb6SAlexander V. Chernikov ipfw_obj_tentry *tent) 2765914bffb6SAlexander V. Chernikov { 2766914bffb6SAlexander V. Chernikov struct fhash_cfg *cfg; 2767914bffb6SAlexander V. Chernikov struct fhashbhead *head; 2768914bffb6SAlexander V. Chernikov struct fhashentry *ent, *tmp; 2769914bffb6SAlexander V. Chernikov struct fhashentry6 fe6; 2770914bffb6SAlexander V. Chernikov struct tentry_info tei; 2771914bffb6SAlexander V. Chernikov int error; 2772914bffb6SAlexander V. Chernikov uint32_t hash; 2773914bffb6SAlexander V. Chernikov size_t sz; 2774914bffb6SAlexander V. Chernikov 2775914bffb6SAlexander V. Chernikov cfg = (struct fhash_cfg *)ta_state; 2776914bffb6SAlexander V. Chernikov 2777914bffb6SAlexander V. Chernikov ent = &fe6.e; 2778914bffb6SAlexander V. Chernikov 2779914bffb6SAlexander V. Chernikov memset(&fe6, 0, sizeof(fe6)); 2780914bffb6SAlexander V. Chernikov memset(&tei, 0, sizeof(tei)); 2781914bffb6SAlexander V. Chernikov 2782914bffb6SAlexander V. Chernikov tei.paddr = &tent->k.flow; 2783914bffb6SAlexander V. Chernikov tei.subtype = tent->subtype; 2784914bffb6SAlexander V. Chernikov 2785914bffb6SAlexander V. Chernikov if ((error = tei_to_fhash_ent(&tei, ent)) != 0) 2786914bffb6SAlexander V. Chernikov return (error); 2787914bffb6SAlexander V. Chernikov 2788914bffb6SAlexander V. Chernikov head = cfg->head; 2789914bffb6SAlexander V. Chernikov hash = hash_flow_ent(ent, cfg->size); 2790914bffb6SAlexander V. Chernikov 2791914bffb6SAlexander V. Chernikov if (tei.subtype == AF_INET) 2792914bffb6SAlexander V. Chernikov sz = 2 * sizeof(struct in_addr); 2793914bffb6SAlexander V. Chernikov else 2794914bffb6SAlexander V. Chernikov sz = 2 * sizeof(struct in6_addr); 2795914bffb6SAlexander V. Chernikov 2796914bffb6SAlexander V. Chernikov /* Check for existence */ 2797914bffb6SAlexander V. Chernikov SLIST_FOREACH(tmp, &head[hash], next) { 2798914bffb6SAlexander V. Chernikov if (cmp_flow_ent(tmp, ent, sz) != 0) { 2799914bffb6SAlexander V. Chernikov ta_dump_fhash_tentry(ta_state, ti, tmp, tent); 2800914bffb6SAlexander V. Chernikov return (0); 2801914bffb6SAlexander V. Chernikov } 2802914bffb6SAlexander V. Chernikov } 2803914bffb6SAlexander V. Chernikov 2804914bffb6SAlexander V. Chernikov return (ENOENT); 2805914bffb6SAlexander V. Chernikov } 2806914bffb6SAlexander V. Chernikov 2807914bffb6SAlexander V. Chernikov static void 2808914bffb6SAlexander V. Chernikov ta_foreach_fhash(void *ta_state, struct table_info *ti, ta_foreach_f *f, 2809914bffb6SAlexander V. Chernikov void *arg) 2810914bffb6SAlexander V. Chernikov { 2811914bffb6SAlexander V. Chernikov struct fhash_cfg *cfg; 2812914bffb6SAlexander V. Chernikov struct fhashentry *ent, *ent_next; 2813914bffb6SAlexander V. Chernikov int i; 2814914bffb6SAlexander V. Chernikov 2815914bffb6SAlexander V. Chernikov cfg = (struct fhash_cfg *)ta_state; 2816914bffb6SAlexander V. Chernikov 2817914bffb6SAlexander V. Chernikov for (i = 0; i < cfg->size; i++) 2818914bffb6SAlexander V. Chernikov SLIST_FOREACH_SAFE(ent, &cfg->head[i], next, ent_next) 2819914bffb6SAlexander V. Chernikov f(ent, arg); 2820914bffb6SAlexander V. Chernikov } 2821914bffb6SAlexander V. Chernikov 2822914bffb6SAlexander V. Chernikov 2823914bffb6SAlexander V. Chernikov struct ta_buf_fhash 2824914bffb6SAlexander V. Chernikov { 2825914bffb6SAlexander V. Chernikov void *ent_ptr; 2826914bffb6SAlexander V. Chernikov struct fhashentry6 fe6; 2827914bffb6SAlexander V. Chernikov }; 2828914bffb6SAlexander V. Chernikov 2829914bffb6SAlexander V. Chernikov static int 2830914bffb6SAlexander V. Chernikov ta_prepare_add_fhash(struct ip_fw_chain *ch, struct tentry_info *tei, 2831914bffb6SAlexander V. Chernikov void *ta_buf) 2832914bffb6SAlexander V. Chernikov { 2833914bffb6SAlexander V. Chernikov struct ta_buf_fhash *tb; 2834914bffb6SAlexander V. Chernikov struct fhashentry *ent; 2835914bffb6SAlexander V. Chernikov size_t sz; 2836914bffb6SAlexander V. Chernikov int error; 2837914bffb6SAlexander V. Chernikov 2838914bffb6SAlexander V. Chernikov tb = (struct ta_buf_fhash *)ta_buf; 2839914bffb6SAlexander V. Chernikov memset(tb, 0, sizeof(struct ta_buf_fhash)); 2840914bffb6SAlexander V. Chernikov 2841914bffb6SAlexander V. Chernikov if (tei->subtype == AF_INET) 2842914bffb6SAlexander V. Chernikov sz = sizeof(struct fhashentry4); 2843914bffb6SAlexander V. Chernikov else if (tei->subtype == AF_INET6) 2844914bffb6SAlexander V. Chernikov sz = sizeof(struct fhashentry6); 2845914bffb6SAlexander V. Chernikov else 2846914bffb6SAlexander V. Chernikov return (EINVAL); 2847914bffb6SAlexander V. Chernikov 2848914bffb6SAlexander V. Chernikov ent = malloc(sz, M_IPFW_TBL, M_WAITOK | M_ZERO); 2849914bffb6SAlexander V. Chernikov 2850914bffb6SAlexander V. Chernikov error = tei_to_fhash_ent(tei, ent); 2851914bffb6SAlexander V. Chernikov if (error != 0) { 2852914bffb6SAlexander V. Chernikov free(ent, M_IPFW_TBL); 2853914bffb6SAlexander V. Chernikov return (error); 2854914bffb6SAlexander V. Chernikov } 2855914bffb6SAlexander V. Chernikov tb->ent_ptr = ent; 2856914bffb6SAlexander V. Chernikov 2857914bffb6SAlexander V. Chernikov return (0); 2858914bffb6SAlexander V. Chernikov } 2859914bffb6SAlexander V. Chernikov 2860914bffb6SAlexander V. Chernikov static int 2861914bffb6SAlexander V. Chernikov ta_add_fhash(void *ta_state, struct table_info *ti, struct tentry_info *tei, 2862914bffb6SAlexander V. Chernikov void *ta_buf, uint64_t *pflags, uint32_t *pnum) 2863914bffb6SAlexander V. Chernikov { 2864914bffb6SAlexander V. Chernikov struct fhash_cfg *cfg; 2865914bffb6SAlexander V. Chernikov struct fhashbhead *head; 2866914bffb6SAlexander V. Chernikov struct fhashentry *ent, *tmp; 2867914bffb6SAlexander V. Chernikov struct ta_buf_fhash *tb; 2868914bffb6SAlexander V. Chernikov int exists; 2869914bffb6SAlexander V. Chernikov uint32_t hash; 2870914bffb6SAlexander V. Chernikov size_t sz; 2871914bffb6SAlexander V. Chernikov 2872914bffb6SAlexander V. Chernikov cfg = (struct fhash_cfg *)ta_state; 2873914bffb6SAlexander V. Chernikov tb = (struct ta_buf_fhash *)ta_buf; 2874914bffb6SAlexander V. Chernikov ent = (struct fhashentry *)tb->ent_ptr; 2875914bffb6SAlexander V. Chernikov exists = 0; 2876914bffb6SAlexander V. Chernikov 2877914bffb6SAlexander V. Chernikov head = cfg->head; 2878914bffb6SAlexander V. Chernikov hash = hash_flow_ent(ent, cfg->size); 2879914bffb6SAlexander V. Chernikov 2880914bffb6SAlexander V. Chernikov if (tei->subtype == AF_INET) 2881914bffb6SAlexander V. Chernikov sz = 2 * sizeof(struct in_addr); 2882914bffb6SAlexander V. Chernikov else 2883914bffb6SAlexander V. Chernikov sz = 2 * sizeof(struct in6_addr); 2884914bffb6SAlexander V. Chernikov 2885914bffb6SAlexander V. Chernikov /* Check for existence */ 2886914bffb6SAlexander V. Chernikov SLIST_FOREACH(tmp, &head[hash], next) { 2887914bffb6SAlexander V. Chernikov if (cmp_flow_ent(tmp, ent, sz) != 0) { 2888914bffb6SAlexander V. Chernikov exists = 1; 2889914bffb6SAlexander V. Chernikov break; 2890914bffb6SAlexander V. Chernikov } 2891914bffb6SAlexander V. Chernikov } 2892914bffb6SAlexander V. Chernikov 2893914bffb6SAlexander V. Chernikov if (exists == 1) { 2894914bffb6SAlexander V. Chernikov if ((tei->flags & TEI_FLAGS_UPDATE) == 0) 2895914bffb6SAlexander V. Chernikov return (EEXIST); 2896914bffb6SAlexander V. Chernikov /* Record already exists. Update value if we're asked to */ 2897914bffb6SAlexander V. Chernikov tmp->value = tei->value; 2898914bffb6SAlexander V. Chernikov /* Indicate that update has happened instead of addition */ 2899914bffb6SAlexander V. Chernikov tei->flags |= TEI_FLAGS_UPDATED; 2900914bffb6SAlexander V. Chernikov *pnum = 0; 2901914bffb6SAlexander V. Chernikov } else { 2902914bffb6SAlexander V. Chernikov SLIST_INSERT_HEAD(&head[hash], ent, next); 2903914bffb6SAlexander V. Chernikov tb->ent_ptr = NULL; 2904914bffb6SAlexander V. Chernikov *pnum = 1; 2905914bffb6SAlexander V. Chernikov 2906914bffb6SAlexander V. Chernikov /* Update counters and check if we need to grow hash */ 2907914bffb6SAlexander V. Chernikov cfg->items++; 2908914bffb6SAlexander V. Chernikov if (cfg->items > cfg->size && cfg->size < 65536) 2909914bffb6SAlexander V. Chernikov *pflags = cfg->size * 2; 2910914bffb6SAlexander V. Chernikov } 2911914bffb6SAlexander V. Chernikov 2912914bffb6SAlexander V. Chernikov return (0); 2913914bffb6SAlexander V. Chernikov } 2914914bffb6SAlexander V. Chernikov 2915914bffb6SAlexander V. Chernikov static int 2916914bffb6SAlexander V. Chernikov ta_prepare_del_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 2921914bffb6SAlexander V. Chernikov tb = (struct ta_buf_fhash *)ta_buf; 2922914bffb6SAlexander V. Chernikov memset(tb, 0, sizeof(struct ta_buf_fhash)); 2923914bffb6SAlexander V. Chernikov 2924914bffb6SAlexander V. Chernikov return (tei_to_fhash_ent(tei, &tb->fe6.e)); 2925914bffb6SAlexander V. Chernikov } 2926914bffb6SAlexander V. Chernikov 2927914bffb6SAlexander V. Chernikov static int 2928914bffb6SAlexander V. Chernikov ta_del_fhash(void *ta_state, struct table_info *ti, struct tentry_info *tei, 2929914bffb6SAlexander V. Chernikov void *ta_buf, uint64_t *pflags, uint32_t *pnum) 2930914bffb6SAlexander V. Chernikov { 2931914bffb6SAlexander V. Chernikov struct fhash_cfg *cfg; 2932914bffb6SAlexander V. Chernikov struct fhashbhead *head; 2933914bffb6SAlexander V. Chernikov struct fhashentry *ent, *tmp; 2934914bffb6SAlexander V. Chernikov struct ta_buf_fhash *tb; 2935914bffb6SAlexander V. Chernikov uint32_t hash; 2936914bffb6SAlexander V. Chernikov size_t sz; 2937914bffb6SAlexander V. Chernikov 2938914bffb6SAlexander V. Chernikov cfg = (struct fhash_cfg *)ta_state; 2939914bffb6SAlexander V. Chernikov tb = (struct ta_buf_fhash *)ta_buf; 2940914bffb6SAlexander V. Chernikov ent = &tb->fe6.e; 2941914bffb6SAlexander V. Chernikov 2942914bffb6SAlexander V. Chernikov head = cfg->head; 2943914bffb6SAlexander V. Chernikov hash = hash_flow_ent(ent, cfg->size); 2944914bffb6SAlexander V. Chernikov 2945914bffb6SAlexander V. Chernikov if (tei->subtype == AF_INET) 2946914bffb6SAlexander V. Chernikov sz = 2 * sizeof(struct in_addr); 2947914bffb6SAlexander V. Chernikov else 2948914bffb6SAlexander V. Chernikov sz = 2 * sizeof(struct in6_addr); 2949914bffb6SAlexander V. Chernikov 2950914bffb6SAlexander V. Chernikov /* Check for existence */ 2951914bffb6SAlexander V. Chernikov SLIST_FOREACH(tmp, &head[hash], next) { 2952914bffb6SAlexander V. Chernikov if (cmp_flow_ent(tmp, ent, sz) != 0) { 2953914bffb6SAlexander V. Chernikov SLIST_REMOVE(&head[hash], tmp, fhashentry, next); 2954914bffb6SAlexander V. Chernikov *pnum = 1; 2955914bffb6SAlexander V. Chernikov cfg->items--; 2956914bffb6SAlexander V. Chernikov return (0); 2957914bffb6SAlexander V. Chernikov } 2958914bffb6SAlexander V. Chernikov } 2959914bffb6SAlexander V. Chernikov 2960914bffb6SAlexander V. Chernikov return (ENOENT); 2961914bffb6SAlexander V. Chernikov } 2962914bffb6SAlexander V. Chernikov 2963914bffb6SAlexander V. Chernikov static void 2964914bffb6SAlexander V. Chernikov ta_flush_fhash_entry(struct ip_fw_chain *ch, struct tentry_info *tei, 2965914bffb6SAlexander V. Chernikov void *ta_buf) 2966914bffb6SAlexander V. Chernikov { 2967914bffb6SAlexander V. Chernikov struct ta_buf_fhash *tb; 2968914bffb6SAlexander V. Chernikov 2969914bffb6SAlexander V. Chernikov tb = (struct ta_buf_fhash *)ta_buf; 2970914bffb6SAlexander V. Chernikov 2971914bffb6SAlexander V. Chernikov if (tb->ent_ptr != NULL) 2972914bffb6SAlexander V. Chernikov free(tb->ent_ptr, M_IPFW_TBL); 2973914bffb6SAlexander V. Chernikov } 2974914bffb6SAlexander V. Chernikov 2975914bffb6SAlexander V. Chernikov /* 2976914bffb6SAlexander V. Chernikov * Hash growing callbacks. 2977914bffb6SAlexander V. Chernikov */ 2978914bffb6SAlexander V. Chernikov 2979914bffb6SAlexander V. Chernikov /* 2980914bffb6SAlexander V. Chernikov * Allocate new, larger fhash. 2981914bffb6SAlexander V. Chernikov */ 2982914bffb6SAlexander V. Chernikov static int 2983914bffb6SAlexander V. Chernikov ta_prepare_mod_fhash(void *ta_buf, uint64_t *pflags) 2984914bffb6SAlexander V. Chernikov { 2985914bffb6SAlexander V. Chernikov struct mod_item *mi; 2986914bffb6SAlexander V. Chernikov struct fhashbhead *head; 2987914bffb6SAlexander V. Chernikov int i; 2988914bffb6SAlexander V. Chernikov 2989914bffb6SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 2990914bffb6SAlexander V. Chernikov 2991914bffb6SAlexander V. Chernikov memset(mi, 0, sizeof(struct mod_item)); 2992914bffb6SAlexander V. Chernikov mi->size = *pflags; 2993914bffb6SAlexander V. Chernikov head = malloc(sizeof(struct fhashbhead) * mi->size, M_IPFW, 2994914bffb6SAlexander V. Chernikov M_WAITOK | M_ZERO); 2995914bffb6SAlexander V. Chernikov for (i = 0; i < mi->size; i++) 2996914bffb6SAlexander V. Chernikov SLIST_INIT(&head[i]); 2997914bffb6SAlexander V. Chernikov 2998914bffb6SAlexander V. Chernikov mi->main_ptr = head; 2999914bffb6SAlexander V. Chernikov 3000914bffb6SAlexander V. Chernikov return (0); 3001914bffb6SAlexander V. Chernikov } 3002914bffb6SAlexander V. Chernikov 3003914bffb6SAlexander V. Chernikov /* 3004914bffb6SAlexander V. Chernikov * Copy data from old runtime array to new one. 3005914bffb6SAlexander V. Chernikov */ 3006914bffb6SAlexander V. Chernikov static int 3007914bffb6SAlexander V. Chernikov ta_fill_mod_fhash(void *ta_state, struct table_info *ti, void *ta_buf, 3008914bffb6SAlexander V. Chernikov uint64_t *pflags) 3009914bffb6SAlexander V. Chernikov { 3010914bffb6SAlexander V. Chernikov 3011914bffb6SAlexander V. Chernikov /* In is not possible to do rehash if we're not holidng WLOCK. */ 3012914bffb6SAlexander V. Chernikov return (0); 3013914bffb6SAlexander V. Chernikov } 3014914bffb6SAlexander V. Chernikov 3015914bffb6SAlexander V. Chernikov 3016914bffb6SAlexander V. Chernikov /* 3017914bffb6SAlexander V. Chernikov * Switch old & new arrays. 3018914bffb6SAlexander V. Chernikov */ 3019914bffb6SAlexander V. Chernikov static int 3020914bffb6SAlexander V. Chernikov ta_modify_fhash(void *ta_state, struct table_info *ti, void *ta_buf, 3021914bffb6SAlexander V. Chernikov uint64_t pflags) 3022914bffb6SAlexander V. Chernikov { 3023914bffb6SAlexander V. Chernikov struct mod_item *mi; 3024914bffb6SAlexander V. Chernikov struct fhash_cfg *cfg; 3025914bffb6SAlexander V. Chernikov struct fhashbhead *old_head, *new_head; 3026914bffb6SAlexander V. Chernikov struct fhashentry *ent, *ent_next; 3027914bffb6SAlexander V. Chernikov int i; 3028914bffb6SAlexander V. Chernikov uint32_t nhash; 3029914bffb6SAlexander V. Chernikov size_t old_size; 3030914bffb6SAlexander V. Chernikov 3031914bffb6SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 3032914bffb6SAlexander V. Chernikov cfg = (struct fhash_cfg *)ta_state; 3033914bffb6SAlexander V. Chernikov 3034914bffb6SAlexander V. Chernikov /* Check which hash we need to grow and do we still need that */ 3035914bffb6SAlexander V. Chernikov old_size = cfg->size; 3036914bffb6SAlexander V. Chernikov old_head = ti->state; 3037914bffb6SAlexander V. Chernikov 3038914bffb6SAlexander V. Chernikov if (old_size >= mi->size) 3039914bffb6SAlexander V. Chernikov return (0); 3040914bffb6SAlexander V. Chernikov 3041914bffb6SAlexander V. Chernikov new_head = (struct fhashbhead *)mi->main_ptr; 3042914bffb6SAlexander V. Chernikov for (i = 0; i < old_size; i++) { 3043914bffb6SAlexander V. Chernikov SLIST_FOREACH_SAFE(ent, &old_head[i], next, ent_next) { 3044914bffb6SAlexander V. Chernikov nhash = hash_flow_ent(ent, mi->size); 3045914bffb6SAlexander V. Chernikov SLIST_INSERT_HEAD(&new_head[nhash], ent, next); 3046914bffb6SAlexander V. Chernikov } 3047914bffb6SAlexander V. Chernikov } 3048914bffb6SAlexander V. Chernikov 3049914bffb6SAlexander V. Chernikov ti->state = new_head; 3050914bffb6SAlexander V. Chernikov ti->data = mi->size; 3051914bffb6SAlexander V. Chernikov cfg->head = new_head; 3052914bffb6SAlexander V. Chernikov cfg->size = mi->size; 3053914bffb6SAlexander V. Chernikov 3054914bffb6SAlexander V. Chernikov mi->main_ptr = old_head; 3055914bffb6SAlexander V. Chernikov 3056914bffb6SAlexander V. Chernikov return (0); 3057914bffb6SAlexander V. Chernikov } 3058914bffb6SAlexander V. Chernikov 3059914bffb6SAlexander V. Chernikov /* 3060914bffb6SAlexander V. Chernikov * Free unneded array. 3061914bffb6SAlexander V. Chernikov */ 3062914bffb6SAlexander V. Chernikov static void 3063914bffb6SAlexander V. Chernikov ta_flush_mod_fhash(void *ta_buf) 3064914bffb6SAlexander V. Chernikov { 3065914bffb6SAlexander V. Chernikov struct mod_item *mi; 3066914bffb6SAlexander V. Chernikov 3067914bffb6SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 3068914bffb6SAlexander V. Chernikov if (mi->main_ptr != NULL) 3069914bffb6SAlexander V. Chernikov free(mi->main_ptr, M_IPFW); 3070914bffb6SAlexander V. Chernikov } 3071914bffb6SAlexander V. Chernikov 3072914bffb6SAlexander V. Chernikov struct table_algo flow_hash = { 3073914bffb6SAlexander V. Chernikov .name = "flow:hash", 3074914bffb6SAlexander V. Chernikov .type = IPFW_TABLE_FLOW, 307557a1cf95SAlexander V. Chernikov .flags = TA_FLAG_DEFAULT, 307657a1cf95SAlexander V. Chernikov .ta_buf_size = sizeof(struct ta_buf_fhash), 3077914bffb6SAlexander V. Chernikov .init = ta_init_fhash, 3078914bffb6SAlexander V. Chernikov .destroy = ta_destroy_fhash, 3079914bffb6SAlexander V. Chernikov .prepare_add = ta_prepare_add_fhash, 3080914bffb6SAlexander V. Chernikov .prepare_del = ta_prepare_del_fhash, 3081914bffb6SAlexander V. Chernikov .add = ta_add_fhash, 3082914bffb6SAlexander V. Chernikov .del = ta_del_fhash, 3083914bffb6SAlexander V. Chernikov .flush_entry = ta_flush_fhash_entry, 3084914bffb6SAlexander V. Chernikov .foreach = ta_foreach_fhash, 3085914bffb6SAlexander V. Chernikov .dump_tentry = ta_dump_fhash_tentry, 3086914bffb6SAlexander V. Chernikov .find_tentry = ta_find_fhash_tentry, 3087914bffb6SAlexander V. Chernikov .prepare_mod = ta_prepare_mod_fhash, 3088914bffb6SAlexander V. Chernikov .fill_mod = ta_fill_mod_fhash, 3089914bffb6SAlexander V. Chernikov .modify = ta_modify_fhash, 3090914bffb6SAlexander V. Chernikov .flush_mod = ta_flush_mod_fhash, 3091914bffb6SAlexander V. Chernikov }; 30929f7d47b0SAlexander V. Chernikov void 30930b565ac0SAlexander V. Chernikov ipfw_table_algo_init(struct ip_fw_chain *ch) 30949f7d47b0SAlexander V. Chernikov { 30950b565ac0SAlexander V. Chernikov size_t sz; 30960b565ac0SAlexander V. Chernikov 30979f7d47b0SAlexander V. Chernikov /* 30989f7d47b0SAlexander V. Chernikov * Register all algorithms presented here. 30999f7d47b0SAlexander V. Chernikov */ 31000b565ac0SAlexander V. Chernikov sz = sizeof(struct table_algo); 31010b565ac0SAlexander V. Chernikov ipfw_add_table_algo(ch, &cidr_radix, sz, &cidr_radix.idx); 31020b565ac0SAlexander V. Chernikov ipfw_add_table_algo(ch, &cidr_hash, sz, &cidr_hash.idx); 31030b565ac0SAlexander V. Chernikov ipfw_add_table_algo(ch, &iface_idx, sz, &iface_idx.idx); 3104b23d5de9SAlexander V. Chernikov ipfw_add_table_algo(ch, &number_array, sz, &number_array.idx); 3105914bffb6SAlexander V. Chernikov ipfw_add_table_algo(ch, &flow_hash, sz, &flow_hash.idx); 31069f7d47b0SAlexander V. Chernikov } 31079f7d47b0SAlexander V. Chernikov 31089f7d47b0SAlexander V. Chernikov void 31090b565ac0SAlexander V. Chernikov ipfw_table_algo_destroy(struct ip_fw_chain *ch) 31109f7d47b0SAlexander V. Chernikov { 31110b565ac0SAlexander V. Chernikov 31120b565ac0SAlexander V. Chernikov ipfw_del_table_algo(ch, cidr_radix.idx); 31130b565ac0SAlexander V. Chernikov ipfw_del_table_algo(ch, cidr_hash.idx); 31140b565ac0SAlexander V. Chernikov ipfw_del_table_algo(ch, iface_idx.idx); 3115b23d5de9SAlexander V. Chernikov ipfw_del_table_algo(ch, number_array.idx); 3116914bffb6SAlexander V. Chernikov ipfw_del_table_algo(ch, flow_hash.idx); 31179f7d47b0SAlexander V. Chernikov } 31189f7d47b0SAlexander V. Chernikov 31199f7d47b0SAlexander V. Chernikov 3120