19f7d47b0SAlexander V. Chernikov /*- 21a33e799SAlexander V. Chernikov * Copyright (c) 2014 Yandex LLC 31a33e799SAlexander V. Chernikov * Copyright (c) 2014 Alexander V. Chernikov 49f7d47b0SAlexander V. Chernikov * 59f7d47b0SAlexander V. Chernikov * Redistribution and use in source and binary forms, with or without 69f7d47b0SAlexander V. Chernikov * modification, are permitted provided that the following conditions 79f7d47b0SAlexander V. Chernikov * are met: 89f7d47b0SAlexander V. Chernikov * 1. Redistributions of source code must retain the above copyright 99f7d47b0SAlexander V. Chernikov * notice, this list of conditions and the following disclaimer. 109f7d47b0SAlexander V. Chernikov * 2. Redistributions in binary form must reproduce the above copyright 119f7d47b0SAlexander V. Chernikov * notice, this list of conditions and the following disclaimer in the 129f7d47b0SAlexander V. Chernikov * documentation and/or other materials provided with the distribution. 139f7d47b0SAlexander V. Chernikov * 149f7d47b0SAlexander V. Chernikov * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 159f7d47b0SAlexander V. Chernikov * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 169f7d47b0SAlexander V. Chernikov * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 179f7d47b0SAlexander V. Chernikov * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 189f7d47b0SAlexander V. Chernikov * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 199f7d47b0SAlexander V. Chernikov * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 209f7d47b0SAlexander V. Chernikov * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 219f7d47b0SAlexander V. Chernikov * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 229f7d47b0SAlexander V. Chernikov * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 239f7d47b0SAlexander V. Chernikov * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 249f7d47b0SAlexander V. Chernikov * SUCH DAMAGE. 259f7d47b0SAlexander V. Chernikov */ 269f7d47b0SAlexander V. Chernikov 279f7d47b0SAlexander V. Chernikov #include <sys/cdefs.h> 28a13a8216SAlexander V. Chernikov __FBSDID("$FreeBSD$"); 299f7d47b0SAlexander V. Chernikov 309f7d47b0SAlexander V. Chernikov /* 319f7d47b0SAlexander V. Chernikov * Lookup table algorithms. 329f7d47b0SAlexander V. Chernikov * 339f7d47b0SAlexander V. Chernikov */ 349f7d47b0SAlexander V. Chernikov 359f7d47b0SAlexander V. Chernikov #include "opt_ipfw.h" 369f7d47b0SAlexander V. Chernikov #include "opt_inet.h" 379f7d47b0SAlexander V. Chernikov #ifndef INET 389f7d47b0SAlexander V. Chernikov #error IPFIREWALL requires INET. 399f7d47b0SAlexander V. Chernikov #endif /* INET */ 409f7d47b0SAlexander V. Chernikov #include "opt_inet6.h" 419f7d47b0SAlexander V. Chernikov 429f7d47b0SAlexander V. Chernikov #include <sys/param.h> 439f7d47b0SAlexander V. Chernikov #include <sys/systm.h> 449f7d47b0SAlexander V. Chernikov #include <sys/malloc.h> 459f7d47b0SAlexander V. Chernikov #include <sys/kernel.h> 469f7d47b0SAlexander V. Chernikov #include <sys/lock.h> 479f7d47b0SAlexander V. Chernikov #include <sys/rwlock.h> 48d4e1b515SAlexander V. Chernikov #include <sys/rmlock.h> 499f7d47b0SAlexander V. Chernikov #include <sys/socket.h> 509f7d47b0SAlexander V. Chernikov #include <sys/queue.h> 519f7d47b0SAlexander V. Chernikov #include <net/if.h> /* ip_fw.h requires IFNAMSIZ */ 529f7d47b0SAlexander V. Chernikov #include <net/radix.h> 53d3b00c08SAlexander V. Chernikov #include <net/route.h> 5461eee0e2SAlexander V. Chernikov #include <net/route_var.h> 559f7d47b0SAlexander V. Chernikov 569f7d47b0SAlexander V. Chernikov #include <netinet/in.h> 57004d3e30SAlexander V. Chernikov #include <netinet/in_fib.h> 589f7d47b0SAlexander V. Chernikov #include <netinet/ip_var.h> /* struct ipfw_rule_ref */ 599f7d47b0SAlexander V. Chernikov #include <netinet/ip_fw.h> 60004d3e30SAlexander V. Chernikov #include <netinet6/in6_fib.h> 619f7d47b0SAlexander V. Chernikov 629f7d47b0SAlexander V. Chernikov #include <netpfil/ipfw/ip_fw_private.h> 63ea761a5dSAlexander V. Chernikov #include <netpfil/ipfw/ip_fw_table.h> 649f7d47b0SAlexander V. Chernikov 65301290bcSAlexander V. Chernikov 66301290bcSAlexander V. Chernikov /* 67301290bcSAlexander V. Chernikov * IPFW table lookup algorithms. 68301290bcSAlexander V. Chernikov * 69301290bcSAlexander V. Chernikov * What is needed to add another table algo? 70301290bcSAlexander V. Chernikov * 71301290bcSAlexander V. Chernikov * Algo init: 72301290bcSAlexander V. Chernikov * * struct table_algo has to be filled with: 73c21034b7SAlexander V. Chernikov * name: "type:algoname" format, e.g. "addr:radix". Currently 74c21034b7SAlexander V. Chernikov * there are the following types: "addr", "iface", "number" and "flow". 75301290bcSAlexander V. Chernikov * type: one of IPFW_TABLE_* types 76301290bcSAlexander V. Chernikov * flags: one or more TA_FLAGS_* 77301290bcSAlexander V. Chernikov * ta_buf_size: size of structure used to store add/del item state. 78301290bcSAlexander V. Chernikov * Needs to be less than TA_BUF_SZ. 79301290bcSAlexander V. Chernikov * callbacks: see below for description. 80301290bcSAlexander V. Chernikov * * ipfw_add_table_algo / ipfw_del_table_algo has to be called 81301290bcSAlexander V. Chernikov * 82301290bcSAlexander V. Chernikov * Callbacks description: 83301290bcSAlexander V. Chernikov * 84301290bcSAlexander V. Chernikov * -init: request to initialize new table instance. 85301290bcSAlexander V. Chernikov * typedef int (ta_init)(struct ip_fw_chain *ch, void **ta_state, 86301290bcSAlexander V. Chernikov * struct table_info *ti, char *data, uint8_t tflags); 87301290bcSAlexander V. Chernikov * MANDATORY, unlocked. (M_WAITOK). Returns 0 on success. 88301290bcSAlexander V. Chernikov * 89301290bcSAlexander V. Chernikov * Allocate all structures needed for normal operations. 90301290bcSAlexander V. Chernikov * * Caller may want to parse @data for some algo-specific 91301290bcSAlexander V. Chernikov * options provided by userland. 92301290bcSAlexander V. Chernikov * * Caller may want to save configuration state pointer to @ta_state 93301290bcSAlexander V. Chernikov * * Caller needs to save desired runtime structure pointer(s) 94301290bcSAlexander V. Chernikov * inside @ti fields. Note that it is not correct to save 95301290bcSAlexander V. Chernikov * @ti pointer at this moment. Use -change_ti hook for that. 96301290bcSAlexander V. Chernikov * * Caller has to fill in ti->lookup to appropriate function 97301290bcSAlexander V. Chernikov * pointer. 98301290bcSAlexander V. Chernikov * 99301290bcSAlexander V. Chernikov * 100301290bcSAlexander V. Chernikov * 101301290bcSAlexander V. Chernikov * -destroy: request to destroy table instance. 102301290bcSAlexander V. Chernikov * typedef void (ta_destroy)(void *ta_state, struct table_info *ti); 1030caab009SAlexander V. Chernikov * MANDATORY, unlocked. (M_WAITOK). 104301290bcSAlexander V. Chernikov * 105301290bcSAlexander V. Chernikov * Frees all table entries and all tables structures allocated by -init. 106301290bcSAlexander V. Chernikov * 107301290bcSAlexander V. Chernikov * 108301290bcSAlexander V. Chernikov * 109301290bcSAlexander V. Chernikov * -prepare_add: request to allocate state for adding new entry. 110301290bcSAlexander V. Chernikov * typedef int (ta_prepare_add)(struct ip_fw_chain *ch, struct tentry_info *tei, 111301290bcSAlexander V. Chernikov * void *ta_buf); 112301290bcSAlexander V. Chernikov * MANDATORY, unlocked. (M_WAITOK). Returns 0 on success. 113301290bcSAlexander V. Chernikov * 11413263632SAlexander V. Chernikov * Allocates state and fills it in with all necessary data (EXCEPT value) 11513263632SAlexander V. Chernikov * from @tei to minimize operations needed to be done under WLOCK. 11613263632SAlexander V. Chernikov * "value" field has to be copied to new entry in @add callback. 117301290bcSAlexander V. Chernikov * Buffer ta_buf of size ta->ta_buf_sz may be used to store 118301290bcSAlexander V. Chernikov * allocated state. 119301290bcSAlexander V. Chernikov * 120301290bcSAlexander V. Chernikov * 121301290bcSAlexander V. Chernikov * 122301290bcSAlexander V. Chernikov * -prepare_del: request to set state for deleting existing entry. 123301290bcSAlexander V. Chernikov * typedef int (ta_prepare_del)(struct ip_fw_chain *ch, struct tentry_info *tei, 124301290bcSAlexander V. Chernikov * void *ta_buf); 125301290bcSAlexander V. Chernikov * MANDATORY, locked, UH. (M_NOWAIT). Returns 0 on success. 126301290bcSAlexander V. Chernikov * 127301290bcSAlexander V. Chernikov * Buffer ta_buf of size ta->ta_buf_sz may be used to store 128301290bcSAlexander V. Chernikov * allocated state. Caller should use on-stack ta_buf allocation 129301290bcSAlexander V. Chernikov * instead of doing malloc(). 130301290bcSAlexander V. Chernikov * 131301290bcSAlexander V. Chernikov * 132301290bcSAlexander V. Chernikov * 133301290bcSAlexander V. Chernikov * -add: request to insert new entry into runtime/config structures. 134301290bcSAlexander V. Chernikov * typedef int (ta_add)(void *ta_state, struct table_info *ti, 135301290bcSAlexander V. Chernikov * struct tentry_info *tei, void *ta_buf, uint32_t *pnum); 136301290bcSAlexander V. Chernikov * MANDATORY, UH+WLOCK. (M_NOWAIT). Returns 0 on success. 137301290bcSAlexander V. Chernikov * 138301290bcSAlexander V. Chernikov * Insert new entry using previously-allocated state in @ta_buf. 139301290bcSAlexander V. Chernikov * * @tei may have the following flags: 140301290bcSAlexander V. Chernikov * TEI_FLAGS_UPDATE: request to add or update entry. 141301290bcSAlexander V. Chernikov * TEI_FLAGS_DONTADD: request to update (but not add) entry. 142301290bcSAlexander V. Chernikov * * Caller is required to do the following: 14313263632SAlexander V. Chernikov * copy real entry value from @tei 144301290bcSAlexander V. Chernikov * entry added: return 0, set 1 to @pnum 145301290bcSAlexander V. Chernikov * entry updated: return 0, store 0 to @pnum, store old value in @tei, 146301290bcSAlexander V. Chernikov * add TEI_FLAGS_UPDATED flag to @tei. 147301290bcSAlexander V. Chernikov * entry exists: return EEXIST 148301290bcSAlexander V. Chernikov * entry not found: return ENOENT 149301290bcSAlexander V. Chernikov * other error: return non-zero error code. 150301290bcSAlexander V. Chernikov * 151301290bcSAlexander V. Chernikov * 152301290bcSAlexander V. Chernikov * 153301290bcSAlexander V. Chernikov * -del: request to delete existing entry from runtime/config structures. 154301290bcSAlexander V. Chernikov * typedef int (ta_del)(void *ta_state, struct table_info *ti, 155301290bcSAlexander V. Chernikov * struct tentry_info *tei, void *ta_buf, uint32_t *pnum); 156301290bcSAlexander V. Chernikov * MANDATORY, UH+WLOCK. (M_NOWAIT). Returns 0 on success. 157301290bcSAlexander V. Chernikov * 158301290bcSAlexander V. Chernikov * Delete entry using previously set up in @ta_buf. 159301290bcSAlexander V. Chernikov * * Caller is required to do the following: 16013263632SAlexander V. Chernikov * entry deleted: return 0, set 1 to @pnum, store old value in @tei. 161301290bcSAlexander V. Chernikov * entry not found: return ENOENT 162301290bcSAlexander V. Chernikov * other error: return non-zero error code. 163301290bcSAlexander V. Chernikov * 164301290bcSAlexander V. Chernikov * 165301290bcSAlexander V. Chernikov * 166301290bcSAlexander V. Chernikov * -flush_entry: flush entry state created by -prepare_add / -del / others 167301290bcSAlexander V. Chernikov * typedef void (ta_flush_entry)(struct ip_fw_chain *ch, 168301290bcSAlexander V. Chernikov * struct tentry_info *tei, void *ta_buf); 169301290bcSAlexander V. Chernikov * MANDATORY, may be locked. (M_NOWAIT). 170301290bcSAlexander V. Chernikov * 171301290bcSAlexander V. Chernikov * Delete state allocated by: 172301290bcSAlexander V. Chernikov * -prepare_add (-add returned EEXIST|UPDATED) 173301290bcSAlexander V. Chernikov * -prepare_del (if any) 174301290bcSAlexander V. Chernikov * -del 175301290bcSAlexander V. Chernikov * * Caller is required to handle empty @ta_buf correctly. 176301290bcSAlexander V. Chernikov * 177301290bcSAlexander V. Chernikov * 178301290bcSAlexander V. Chernikov * -find_tentry: finds entry specified by key @tei 179301290bcSAlexander V. Chernikov * typedef int ta_find_tentry(void *ta_state, struct table_info *ti, 180301290bcSAlexander V. Chernikov * ipfw_obj_tentry *tent); 181301290bcSAlexander V. Chernikov * OPTIONAL, locked (UH). (M_NOWAIT). Returns 0 on success. 182301290bcSAlexander V. Chernikov * 183301290bcSAlexander V. Chernikov * Finds entry specified by given key. 184a4641f4eSPedro F. Giffuni * * Caller is required to do the following: 185301290bcSAlexander V. Chernikov * entry found: returns 0, export entry to @tent 186301290bcSAlexander V. Chernikov * entry not found: returns ENOENT 187301290bcSAlexander V. Chernikov * 188301290bcSAlexander V. Chernikov * 189301290bcSAlexander V. Chernikov * -need_modify: checks if @ti has enough space to hold another @count items. 190301290bcSAlexander V. Chernikov * typedef int (ta_need_modify)(void *ta_state, struct table_info *ti, 191301290bcSAlexander V. Chernikov * uint32_t count, uint64_t *pflags); 192fd0869d5SAlexander V. Chernikov * OPTIONAL, locked (UH). (M_NOWAIT). Returns 0 if has. 193301290bcSAlexander V. Chernikov * 194301290bcSAlexander V. Chernikov * Checks if given table has enough space to add @count items without 195301290bcSAlexander V. Chernikov * resize. Caller may use @pflags to store desired modification data. 196301290bcSAlexander V. Chernikov * 197301290bcSAlexander V. Chernikov * 198301290bcSAlexander V. Chernikov * 199301290bcSAlexander V. Chernikov * -prepare_mod: allocate structures for table modification. 200301290bcSAlexander V. Chernikov * typedef int (ta_prepare_mod)(void *ta_buf, uint64_t *pflags); 201fd0869d5SAlexander V. Chernikov * OPTIONAL(need_modify), unlocked. (M_WAITOK). Returns 0 on success. 202301290bcSAlexander V. Chernikov * 203301290bcSAlexander V. Chernikov * Allocate all needed state for table modification. Caller 204301290bcSAlexander V. Chernikov * should use `struct mod_item` to store new state in @ta_buf. 205301290bcSAlexander V. Chernikov * Up to TA_BUF_SZ (128 bytes) can be stored in @ta_buf. 206301290bcSAlexander V. Chernikov * 207301290bcSAlexander V. Chernikov * 208301290bcSAlexander V. Chernikov * 209301290bcSAlexander V. Chernikov * -fill_mod: copy some data to new state/ 210301290bcSAlexander V. Chernikov * typedef int (ta_fill_mod)(void *ta_state, struct table_info *ti, 211301290bcSAlexander V. Chernikov * void *ta_buf, uint64_t *pflags); 212fd0869d5SAlexander V. Chernikov * OPTIONAL(need_modify), locked (UH). (M_NOWAIT). Returns 0 on success. 213301290bcSAlexander V. Chernikov * 214301290bcSAlexander V. Chernikov * Copy as much data as we can to minimize changes under WLOCK. 215301290bcSAlexander V. Chernikov * For example, array can be merged inside this callback. 216301290bcSAlexander V. Chernikov * 217301290bcSAlexander V. Chernikov * 218301290bcSAlexander V. Chernikov * 219301290bcSAlexander V. Chernikov * -modify: perform final modification. 220301290bcSAlexander V. Chernikov * typedef void (ta_modify)(void *ta_state, struct table_info *ti, 221301290bcSAlexander V. Chernikov * void *ta_buf, uint64_t pflags); 222fd0869d5SAlexander V. Chernikov * OPTIONAL(need_modify), locked (UH+WLOCK). (M_NOWAIT). 223301290bcSAlexander V. Chernikov * 224301290bcSAlexander V. Chernikov * Performs all changes necessary to switch to new structures. 225301290bcSAlexander V. Chernikov * * Caller should save old pointers to @ta_buf storage. 226301290bcSAlexander V. Chernikov * 227301290bcSAlexander V. Chernikov * 228301290bcSAlexander V. Chernikov * 229301290bcSAlexander V. Chernikov * -flush_mod: flush table modification state. 230301290bcSAlexander V. Chernikov * typedef void (ta_flush_mod)(void *ta_buf); 231fd0869d5SAlexander V. Chernikov * OPTIONAL(need_modify), unlocked. (M_WAITOK). 232301290bcSAlexander V. Chernikov * 233301290bcSAlexander V. Chernikov * Performs flush for the following: 234301290bcSAlexander V. Chernikov * - prepare_mod (modification was not necessary) 235301290bcSAlexander V. Chernikov * - modify (for the old state) 236301290bcSAlexander V. Chernikov * 237301290bcSAlexander V. Chernikov * 238301290bcSAlexander V. Chernikov * 239301290bcSAlexander V. Chernikov * -change_gi: monitor table info pointer changes 240301290bcSAlexander V. Chernikov * typedef void (ta_change_ti)(void *ta_state, struct table_info *ti); 241301290bcSAlexander V. Chernikov * OPTIONAL, locked (UH). (M_NOWAIT). 242301290bcSAlexander V. Chernikov * 243301290bcSAlexander V. Chernikov * Called on @ti pointer changed. Called immediately after -init 244301290bcSAlexander V. Chernikov * to set initial state. 245301290bcSAlexander V. Chernikov * 246301290bcSAlexander V. Chernikov * 247301290bcSAlexander V. Chernikov * 248301290bcSAlexander V. Chernikov * -foreach: calls @f for each table entry 249301290bcSAlexander V. Chernikov * typedef void ta_foreach(void *ta_state, struct table_info *ti, 250301290bcSAlexander V. Chernikov * ta_foreach_f *f, void *arg); 251301290bcSAlexander V. Chernikov * MANDATORY, locked(UH). (M_NOWAIT). 252301290bcSAlexander V. Chernikov * 253301290bcSAlexander V. Chernikov * Runs callback with specified argument for each table entry, 254301290bcSAlexander V. Chernikov * Typically used for dumping table entries. 255301290bcSAlexander V. Chernikov * 256301290bcSAlexander V. Chernikov * 257301290bcSAlexander V. Chernikov * 258301290bcSAlexander V. Chernikov * -dump_tentry: dump table entry in current @tentry format. 259301290bcSAlexander V. Chernikov * typedef int ta_dump_tentry(void *ta_state, struct table_info *ti, void *e, 260301290bcSAlexander V. Chernikov * ipfw_obj_tentry *tent); 261301290bcSAlexander V. Chernikov * MANDATORY, locked(UH). (M_NOWAIT). Returns 0 on success. 262301290bcSAlexander V. Chernikov * 263301290bcSAlexander V. Chernikov * Dumps entry @e to @tent. 264301290bcSAlexander V. Chernikov * 265301290bcSAlexander V. Chernikov * 266a4641f4eSPedro F. Giffuni * -print_config: prints custom algorithm options into buffer. 267301290bcSAlexander V. Chernikov * typedef void (ta_print_config)(void *ta_state, struct table_info *ti, 268301290bcSAlexander V. Chernikov * char *buf, size_t bufsize); 269301290bcSAlexander V. Chernikov * OPTIONAL. locked(UH). (M_NOWAIT). 270301290bcSAlexander V. Chernikov * 271301290bcSAlexander V. Chernikov * Prints custom algorithm options in the format suitable to pass 272301290bcSAlexander V. Chernikov * back to -init callback. 273301290bcSAlexander V. Chernikov * 274301290bcSAlexander V. Chernikov * 275301290bcSAlexander V. Chernikov * 276301290bcSAlexander V. Chernikov * -dump_tinfo: dumps algo-specific info. 277301290bcSAlexander V. Chernikov * typedef void ta_dump_tinfo(void *ta_state, struct table_info *ti, 278301290bcSAlexander V. Chernikov * ipfw_ta_tinfo *tinfo); 279301290bcSAlexander V. Chernikov * OPTIONAL. locked(UH). (M_NOWAIT). 280301290bcSAlexander V. Chernikov * 281301290bcSAlexander V. Chernikov * Dumps options like items size/hash size, etc. 282301290bcSAlexander V. Chernikov */ 283301290bcSAlexander V. Chernikov 284b1d105bcSAlexander V. Chernikov MALLOC_DEFINE(M_IPFW_TBL, "ipfw_tbl", "IpFw tables"); 2859f7d47b0SAlexander V. Chernikov 2860bce0c23SAlexander V. Chernikov /* 2870bce0c23SAlexander V. Chernikov * Utility structures/functions common to more than one algo 2880bce0c23SAlexander V. Chernikov */ 2890bce0c23SAlexander V. Chernikov 2900bce0c23SAlexander V. Chernikov struct mod_item { 2910bce0c23SAlexander V. Chernikov void *main_ptr; 2920bce0c23SAlexander V. Chernikov size_t size; 2930bce0c23SAlexander V. Chernikov void *main_ptr6; 2940bce0c23SAlexander V. Chernikov size_t size6; 2950bce0c23SAlexander V. Chernikov }; 2960bce0c23SAlexander V. Chernikov 29768394ec8SAlexander V. Chernikov static int badd(const void *key, void *item, void *base, size_t nmemb, 29868394ec8SAlexander V. Chernikov size_t size, int (*compar) (const void *, const void *)); 29968394ec8SAlexander V. Chernikov static int bdel(const void *key, void *base, size_t nmemb, size_t size, 30068394ec8SAlexander V. Chernikov int (*compar) (const void *, const void *)); 30168394ec8SAlexander V. Chernikov 30268394ec8SAlexander V. Chernikov 30368394ec8SAlexander V. Chernikov /* 304c21034b7SAlexander V. Chernikov * ADDR implementation using radix 30568394ec8SAlexander V. Chernikov * 30668394ec8SAlexander V. Chernikov */ 30768394ec8SAlexander V. Chernikov 3089f7d47b0SAlexander V. Chernikov /* 3099f7d47b0SAlexander V. Chernikov * The radix code expects addr and mask to be array of bytes, 3109f7d47b0SAlexander V. Chernikov * with the first byte being the length of the array. rn_inithead 3119f7d47b0SAlexander V. Chernikov * is called with the offset in bits of the lookup key within the 3129f7d47b0SAlexander V. Chernikov * array. If we use a sockaddr_in as the underlying type, 3139f7d47b0SAlexander V. Chernikov * sin_len is conveniently located at offset 0, sin_addr is at 3149f7d47b0SAlexander V. Chernikov * offset 4 and normally aligned. 3159f7d47b0SAlexander V. Chernikov * But for portability, let's avoid assumption and make the code explicit 3169f7d47b0SAlexander V. Chernikov */ 3179f7d47b0SAlexander V. Chernikov #define KEY_LEN(v) *((uint8_t *)&(v)) 3189f7d47b0SAlexander V. Chernikov /* 3199f7d47b0SAlexander V. Chernikov * Do not require radix to compare more than actual IPv4/IPv6 address 3209f7d47b0SAlexander V. Chernikov */ 3219f7d47b0SAlexander V. Chernikov #define KEY_LEN_INET (offsetof(struct sockaddr_in, sin_addr) + sizeof(in_addr_t)) 322e0a8b9eeSAlexander V. Chernikov #define KEY_LEN_INET6 (offsetof(struct sa_in6, sin6_addr) + sizeof(struct in6_addr)) 3239f7d47b0SAlexander V. Chernikov 3249f7d47b0SAlexander V. Chernikov #define OFF_LEN_INET (8 * offsetof(struct sockaddr_in, sin_addr)) 325e0a8b9eeSAlexander V. Chernikov #define OFF_LEN_INET6 (8 * offsetof(struct sa_in6, sin6_addr)) 3269f7d47b0SAlexander V. Chernikov 327c21034b7SAlexander V. Chernikov struct radix_addr_entry { 3289f7d47b0SAlexander V. Chernikov struct radix_node rn[2]; 329e0a8b9eeSAlexander V. Chernikov struct sockaddr_in addr; 330e0a8b9eeSAlexander V. Chernikov uint32_t value; 331e0a8b9eeSAlexander V. Chernikov uint8_t masklen; 332e0a8b9eeSAlexander V. Chernikov }; 333e0a8b9eeSAlexander V. Chernikov 334e0a8b9eeSAlexander V. Chernikov struct sa_in6 { 335e0a8b9eeSAlexander V. Chernikov uint8_t sin6_len; 336e0a8b9eeSAlexander V. Chernikov uint8_t sin6_family; 337e0a8b9eeSAlexander V. Chernikov uint8_t pad[2]; 338e0a8b9eeSAlexander V. Chernikov struct in6_addr sin6_addr; 339e0a8b9eeSAlexander V. Chernikov }; 340e0a8b9eeSAlexander V. Chernikov 341c21034b7SAlexander V. Chernikov struct radix_addr_xentry { 342e0a8b9eeSAlexander V. Chernikov struct radix_node rn[2]; 343e0a8b9eeSAlexander V. Chernikov struct sa_in6 addr6; 344e0a8b9eeSAlexander V. Chernikov uint32_t value; 345e0a8b9eeSAlexander V. Chernikov uint8_t masklen; 3469f7d47b0SAlexander V. Chernikov }; 3479f7d47b0SAlexander V. Chernikov 3485f379342SAlexander V. Chernikov struct radix_cfg { 3495f379342SAlexander V. Chernikov struct radix_node_head *head4; 3505f379342SAlexander V. Chernikov struct radix_node_head *head6; 3515f379342SAlexander V. Chernikov size_t count4; 3525f379342SAlexander V. Chernikov size_t count6; 3535f379342SAlexander V. Chernikov }; 3545f379342SAlexander V. Chernikov 355c21034b7SAlexander V. Chernikov struct ta_buf_radix 3560bce0c23SAlexander V. Chernikov { 3570bce0c23SAlexander V. Chernikov void *ent_ptr; 3580bce0c23SAlexander V. Chernikov struct sockaddr *addr_ptr; 3590bce0c23SAlexander V. Chernikov struct sockaddr *mask_ptr; 3600bce0c23SAlexander V. Chernikov union { 3610bce0c23SAlexander V. Chernikov struct { 3620bce0c23SAlexander V. Chernikov struct sockaddr_in sa; 3630bce0c23SAlexander V. Chernikov struct sockaddr_in ma; 3640bce0c23SAlexander V. Chernikov } a4; 3650bce0c23SAlexander V. Chernikov struct { 3660bce0c23SAlexander V. Chernikov struct sa_in6 sa; 3670bce0c23SAlexander V. Chernikov struct sa_in6 ma; 3680bce0c23SAlexander V. Chernikov } a6; 3690bce0c23SAlexander V. Chernikov } addr; 3700bce0c23SAlexander V. Chernikov }; 3710bce0c23SAlexander V. Chernikov 3729fe15d06SAlexander V. Chernikov static int ta_lookup_radix(struct table_info *ti, void *key, uint32_t keylen, 3739fe15d06SAlexander V. Chernikov uint32_t *val); 3749fe15d06SAlexander V. Chernikov static int ta_init_radix(struct ip_fw_chain *ch, void **ta_state, 3759fe15d06SAlexander V. Chernikov struct table_info *ti, char *data, uint8_t tflags); 3769fe15d06SAlexander V. Chernikov static int flush_radix_entry(struct radix_node *rn, void *arg); 3779fe15d06SAlexander V. Chernikov static void ta_destroy_radix(void *ta_state, struct table_info *ti); 3789fe15d06SAlexander V. Chernikov static void ta_dump_radix_tinfo(void *ta_state, struct table_info *ti, 3799fe15d06SAlexander V. Chernikov ipfw_ta_tinfo *tinfo); 3809fe15d06SAlexander V. Chernikov static int ta_dump_radix_tentry(void *ta_state, struct table_info *ti, 3819fe15d06SAlexander V. Chernikov void *e, ipfw_obj_tentry *tent); 3829fe15d06SAlexander V. Chernikov static int ta_find_radix_tentry(void *ta_state, struct table_info *ti, 3839fe15d06SAlexander V. Chernikov ipfw_obj_tentry *tent); 3849fe15d06SAlexander V. Chernikov static void ta_foreach_radix(void *ta_state, struct table_info *ti, 3859fe15d06SAlexander V. Chernikov ta_foreach_f *f, void *arg); 3869fe15d06SAlexander V. Chernikov static void tei_to_sockaddr_ent(struct tentry_info *tei, struct sockaddr *sa, 3879fe15d06SAlexander V. Chernikov struct sockaddr *ma, int *set_mask); 3889fe15d06SAlexander V. Chernikov static int ta_prepare_add_radix(struct ip_fw_chain *ch, struct tentry_info *tei, 3899fe15d06SAlexander V. Chernikov void *ta_buf); 3909fe15d06SAlexander V. Chernikov static int ta_add_radix(void *ta_state, struct table_info *ti, 3919fe15d06SAlexander V. Chernikov struct tentry_info *tei, void *ta_buf, uint32_t *pnum); 3929fe15d06SAlexander V. Chernikov static int ta_prepare_del_radix(struct ip_fw_chain *ch, struct tentry_info *tei, 3939fe15d06SAlexander V. Chernikov void *ta_buf); 3949fe15d06SAlexander V. Chernikov static int ta_del_radix(void *ta_state, struct table_info *ti, 3959fe15d06SAlexander V. Chernikov struct tentry_info *tei, void *ta_buf, uint32_t *pnum); 3969fe15d06SAlexander V. Chernikov static void ta_flush_radix_entry(struct ip_fw_chain *ch, struct tentry_info *tei, 3979fe15d06SAlexander V. Chernikov void *ta_buf); 3989fe15d06SAlexander V. Chernikov static int ta_need_modify_radix(void *ta_state, struct table_info *ti, 3999fe15d06SAlexander V. Chernikov uint32_t count, uint64_t *pflags); 4009fe15d06SAlexander V. Chernikov 4019f7d47b0SAlexander V. Chernikov static int 4029f7d47b0SAlexander V. Chernikov ta_lookup_radix(struct table_info *ti, void *key, uint32_t keylen, 4039f7d47b0SAlexander V. Chernikov uint32_t *val) 4049f7d47b0SAlexander V. Chernikov { 4059f7d47b0SAlexander V. Chernikov struct radix_node_head *rnh; 4069f7d47b0SAlexander V. Chernikov 4079f7d47b0SAlexander V. Chernikov if (keylen == sizeof(in_addr_t)) { 408c21034b7SAlexander V. Chernikov struct radix_addr_entry *ent; 4099f7d47b0SAlexander V. Chernikov struct sockaddr_in sa; 4109f7d47b0SAlexander V. Chernikov KEY_LEN(sa) = KEY_LEN_INET; 4119f7d47b0SAlexander V. Chernikov sa.sin_addr.s_addr = *((in_addr_t *)key); 4129f7d47b0SAlexander V. Chernikov rnh = (struct radix_node_head *)ti->state; 41361eee0e2SAlexander V. Chernikov ent = (struct radix_addr_entry *)(rnh->rnh_matchaddr(&sa, &rnh->rh)); 4149f7d47b0SAlexander V. Chernikov if (ent != NULL) { 4159f7d47b0SAlexander V. Chernikov *val = ent->value; 4169f7d47b0SAlexander V. Chernikov return (1); 4179f7d47b0SAlexander V. Chernikov } 4189f7d47b0SAlexander V. Chernikov } else { 419c21034b7SAlexander V. Chernikov struct radix_addr_xentry *xent; 420e0a8b9eeSAlexander V. Chernikov struct sa_in6 sa6; 4219f7d47b0SAlexander V. Chernikov KEY_LEN(sa6) = KEY_LEN_INET6; 4229f7d47b0SAlexander V. Chernikov memcpy(&sa6.sin6_addr, key, sizeof(struct in6_addr)); 4239f7d47b0SAlexander V. Chernikov rnh = (struct radix_node_head *)ti->xstate; 42461eee0e2SAlexander V. Chernikov xent = (struct radix_addr_xentry *)(rnh->rnh_matchaddr(&sa6, &rnh->rh)); 4259f7d47b0SAlexander V. Chernikov if (xent != NULL) { 4269f7d47b0SAlexander V. Chernikov *val = xent->value; 4279f7d47b0SAlexander V. Chernikov return (1); 4289f7d47b0SAlexander V. Chernikov } 4299f7d47b0SAlexander V. Chernikov } 4309f7d47b0SAlexander V. Chernikov 4319f7d47b0SAlexander V. Chernikov return (0); 4329f7d47b0SAlexander V. Chernikov } 4339f7d47b0SAlexander V. Chernikov 4349f7d47b0SAlexander V. Chernikov /* 4359f7d47b0SAlexander V. Chernikov * New table 4369f7d47b0SAlexander V. Chernikov */ 4379f7d47b0SAlexander V. Chernikov static int 43868394ec8SAlexander V. Chernikov ta_init_radix(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti, 439914bffb6SAlexander V. Chernikov char *data, uint8_t tflags) 4409f7d47b0SAlexander V. Chernikov { 4415f379342SAlexander V. Chernikov struct radix_cfg *cfg; 4429f7d47b0SAlexander V. Chernikov 4439f7d47b0SAlexander V. Chernikov if (!rn_inithead(&ti->state, OFF_LEN_INET)) 4449f7d47b0SAlexander V. Chernikov return (ENOMEM); 4459f7d47b0SAlexander V. Chernikov if (!rn_inithead(&ti->xstate, OFF_LEN_INET6)) { 4469f7d47b0SAlexander V. Chernikov rn_detachhead(&ti->state); 4479f7d47b0SAlexander V. Chernikov return (ENOMEM); 4489f7d47b0SAlexander V. Chernikov } 4499f7d47b0SAlexander V. Chernikov 4505f379342SAlexander V. Chernikov cfg = malloc(sizeof(struct radix_cfg), M_IPFW, M_WAITOK | M_ZERO); 4515f379342SAlexander V. Chernikov 4525f379342SAlexander V. Chernikov *ta_state = cfg; 4539f7d47b0SAlexander V. Chernikov ti->lookup = ta_lookup_radix; 4549f7d47b0SAlexander V. Chernikov 4559f7d47b0SAlexander V. Chernikov return (0); 4569f7d47b0SAlexander V. Chernikov } 4579f7d47b0SAlexander V. Chernikov 4589f7d47b0SAlexander V. Chernikov static int 459a399f8beSAlexander V. Chernikov flush_radix_entry(struct radix_node *rn, void *arg) 4609f7d47b0SAlexander V. Chernikov { 4619f7d47b0SAlexander V. Chernikov struct radix_node_head * const rnh = arg; 462c21034b7SAlexander V. Chernikov struct radix_addr_entry *ent; 4639f7d47b0SAlexander V. Chernikov 464c21034b7SAlexander V. Chernikov ent = (struct radix_addr_entry *) 46561eee0e2SAlexander V. Chernikov rnh->rnh_deladdr(rn->rn_key, rn->rn_mask, &rnh->rh); 4669f7d47b0SAlexander V. Chernikov if (ent != NULL) 4679f7d47b0SAlexander V. Chernikov free(ent, M_IPFW_TBL); 4689f7d47b0SAlexander V. Chernikov return (0); 4699f7d47b0SAlexander V. Chernikov } 4709f7d47b0SAlexander V. Chernikov 4719f7d47b0SAlexander V. Chernikov static void 4729f7d47b0SAlexander V. Chernikov ta_destroy_radix(void *ta_state, struct table_info *ti) 4739f7d47b0SAlexander V. Chernikov { 4745f379342SAlexander V. Chernikov struct radix_cfg *cfg; 4759f7d47b0SAlexander V. Chernikov struct radix_node_head *rnh; 4769f7d47b0SAlexander V. Chernikov 4775f379342SAlexander V. Chernikov cfg = (struct radix_cfg *)ta_state; 4785f379342SAlexander V. Chernikov 4799f7d47b0SAlexander V. Chernikov rnh = (struct radix_node_head *)(ti->state); 48061eee0e2SAlexander V. Chernikov rnh->rnh_walktree(&rnh->rh, flush_radix_entry, rnh); 4819f7d47b0SAlexander V. Chernikov rn_detachhead(&ti->state); 4829f7d47b0SAlexander V. Chernikov 4839f7d47b0SAlexander V. Chernikov rnh = (struct radix_node_head *)(ti->xstate); 48461eee0e2SAlexander V. Chernikov rnh->rnh_walktree(&rnh->rh, flush_radix_entry, rnh); 4859f7d47b0SAlexander V. Chernikov rn_detachhead(&ti->xstate); 4865f379342SAlexander V. Chernikov 4875f379342SAlexander V. Chernikov free(cfg, M_IPFW); 4885f379342SAlexander V. Chernikov } 4895f379342SAlexander V. Chernikov 4905f379342SAlexander V. Chernikov /* 4915f379342SAlexander V. Chernikov * Provide algo-specific table info 4925f379342SAlexander V. Chernikov */ 4935f379342SAlexander V. Chernikov static void 4945f379342SAlexander V. Chernikov ta_dump_radix_tinfo(void *ta_state, struct table_info *ti, ipfw_ta_tinfo *tinfo) 4955f379342SAlexander V. Chernikov { 4965f379342SAlexander V. Chernikov struct radix_cfg *cfg; 4975f379342SAlexander V. Chernikov 4985f379342SAlexander V. Chernikov cfg = (struct radix_cfg *)ta_state; 4995f379342SAlexander V. Chernikov 5005f379342SAlexander V. Chernikov tinfo->flags = IPFW_TATFLAGS_AFDATA | IPFW_TATFLAGS_AFITEM; 5015f379342SAlexander V. Chernikov tinfo->taclass4 = IPFW_TACLASS_RADIX; 5025f379342SAlexander V. Chernikov tinfo->count4 = cfg->count4; 503c21034b7SAlexander V. Chernikov tinfo->itemsize4 = sizeof(struct radix_addr_entry); 5045f379342SAlexander V. Chernikov tinfo->taclass6 = IPFW_TACLASS_RADIX; 5055f379342SAlexander V. Chernikov tinfo->count6 = cfg->count6; 506c21034b7SAlexander V. Chernikov tinfo->itemsize6 = sizeof(struct radix_addr_xentry); 5079f7d47b0SAlexander V. Chernikov } 5089f7d47b0SAlexander V. Chernikov 5099f7d47b0SAlexander V. Chernikov static int 51081d3153dSAlexander V. Chernikov ta_dump_radix_tentry(void *ta_state, struct table_info *ti, void *e, 51181d3153dSAlexander V. Chernikov ipfw_obj_tentry *tent) 5129f7d47b0SAlexander V. Chernikov { 513c21034b7SAlexander V. Chernikov struct radix_addr_entry *n; 5149fe15d06SAlexander V. Chernikov #ifdef INET6 515c21034b7SAlexander V. Chernikov struct radix_addr_xentry *xn; 5169fe15d06SAlexander V. Chernikov #endif 5179f7d47b0SAlexander V. Chernikov 518c21034b7SAlexander V. Chernikov n = (struct radix_addr_entry *)e; 5199f7d47b0SAlexander V. Chernikov 5209f7d47b0SAlexander V. Chernikov /* Guess IPv4/IPv6 radix by sockaddr family */ 5219f7d47b0SAlexander V. Chernikov if (n->addr.sin_family == AF_INET) { 52281d3153dSAlexander V. Chernikov tent->k.addr.s_addr = n->addr.sin_addr.s_addr; 523e0a8b9eeSAlexander V. Chernikov tent->masklen = n->masklen; 52481d3153dSAlexander V. Chernikov tent->subtype = AF_INET; 5250cba2b28SAlexander V. Chernikov tent->v.kidx = n->value; 5269f7d47b0SAlexander V. Chernikov #ifdef INET6 5279f7d47b0SAlexander V. Chernikov } else { 528c21034b7SAlexander V. Chernikov xn = (struct radix_addr_xentry *)e; 529ba3e1361SAndrey V. Elsukov memcpy(&tent->k.addr6, &xn->addr6.sin6_addr, 530ba3e1361SAndrey V. Elsukov sizeof(struct in6_addr)); 531e0a8b9eeSAlexander V. Chernikov tent->masklen = xn->masklen; 53281d3153dSAlexander V. Chernikov tent->subtype = AF_INET6; 5330cba2b28SAlexander V. Chernikov tent->v.kidx = xn->value; 5349f7d47b0SAlexander V. Chernikov #endif 5359f7d47b0SAlexander V. Chernikov } 5369f7d47b0SAlexander V. Chernikov 5379f7d47b0SAlexander V. Chernikov return (0); 5389f7d47b0SAlexander V. Chernikov } 5399f7d47b0SAlexander V. Chernikov 54081d3153dSAlexander V. Chernikov static int 541914bffb6SAlexander V. Chernikov ta_find_radix_tentry(void *ta_state, struct table_info *ti, 542914bffb6SAlexander V. Chernikov ipfw_obj_tentry *tent) 54381d3153dSAlexander V. Chernikov { 54481d3153dSAlexander V. Chernikov struct radix_node_head *rnh; 54581d3153dSAlexander V. Chernikov void *e; 54681d3153dSAlexander V. Chernikov 54781d3153dSAlexander V. Chernikov e = NULL; 548914bffb6SAlexander V. Chernikov if (tent->subtype == AF_INET) { 54981d3153dSAlexander V. Chernikov struct sockaddr_in sa; 55081d3153dSAlexander V. Chernikov KEY_LEN(sa) = KEY_LEN_INET; 551914bffb6SAlexander V. Chernikov sa.sin_addr.s_addr = tent->k.addr.s_addr; 55281d3153dSAlexander V. Chernikov rnh = (struct radix_node_head *)ti->state; 55361eee0e2SAlexander V. Chernikov e = rnh->rnh_matchaddr(&sa, &rnh->rh); 55481d3153dSAlexander V. Chernikov } else { 555e0a8b9eeSAlexander V. Chernikov struct sa_in6 sa6; 55681d3153dSAlexander V. Chernikov KEY_LEN(sa6) = KEY_LEN_INET6; 557914bffb6SAlexander V. Chernikov memcpy(&sa6.sin6_addr, &tent->k.addr6, sizeof(struct in6_addr)); 55881d3153dSAlexander V. Chernikov rnh = (struct radix_node_head *)ti->xstate; 55961eee0e2SAlexander V. Chernikov e = rnh->rnh_matchaddr(&sa6, &rnh->rh); 56081d3153dSAlexander V. Chernikov } 56181d3153dSAlexander V. Chernikov 56281d3153dSAlexander V. Chernikov if (e != NULL) { 56381d3153dSAlexander V. Chernikov ta_dump_radix_tentry(ta_state, ti, e, tent); 56481d3153dSAlexander V. Chernikov return (0); 56581d3153dSAlexander V. Chernikov } 56681d3153dSAlexander V. Chernikov 56781d3153dSAlexander V. Chernikov return (ENOENT); 56881d3153dSAlexander V. Chernikov } 56981d3153dSAlexander V. Chernikov 5709f7d47b0SAlexander V. Chernikov static void 5719f7d47b0SAlexander V. Chernikov ta_foreach_radix(void *ta_state, struct table_info *ti, ta_foreach_f *f, 5729f7d47b0SAlexander V. Chernikov void *arg) 5739f7d47b0SAlexander V. Chernikov { 5749f7d47b0SAlexander V. Chernikov struct radix_node_head *rnh; 5759f7d47b0SAlexander V. Chernikov 5769f7d47b0SAlexander V. Chernikov rnh = (struct radix_node_head *)(ti->state); 57761eee0e2SAlexander V. Chernikov rnh->rnh_walktree(&rnh->rh, (walktree_f_t *)f, arg); 5789f7d47b0SAlexander V. Chernikov 5799f7d47b0SAlexander V. Chernikov rnh = (struct radix_node_head *)(ti->xstate); 58061eee0e2SAlexander V. Chernikov rnh->rnh_walktree(&rnh->rh, (walktree_f_t *)f, arg); 5819f7d47b0SAlexander V. Chernikov } 5829f7d47b0SAlexander V. Chernikov 5839f7d47b0SAlexander V. Chernikov 5849f7d47b0SAlexander V. Chernikov #ifdef INET6 585d699ee2dSAlexander V. Chernikov static inline void ipv6_writemask(struct in6_addr *addr6, uint8_t mask); 586d699ee2dSAlexander V. Chernikov 5879f7d47b0SAlexander V. Chernikov static inline void 5889f7d47b0SAlexander V. Chernikov ipv6_writemask(struct in6_addr *addr6, uint8_t mask) 5899f7d47b0SAlexander V. Chernikov { 5909f7d47b0SAlexander V. Chernikov uint32_t *cp; 5919f7d47b0SAlexander V. Chernikov 5929f7d47b0SAlexander V. Chernikov for (cp = (uint32_t *)addr6; mask >= 32; mask -= 32) 5939f7d47b0SAlexander V. Chernikov *cp++ = 0xFFFFFFFF; 59437aefa2aSAlexander V. Chernikov if (mask > 0) 5959f7d47b0SAlexander V. Chernikov *cp = htonl(mask ? ~((1 << (32 - mask)) - 1) : 0); 5969f7d47b0SAlexander V. Chernikov } 5979f7d47b0SAlexander V. Chernikov #endif 5989f7d47b0SAlexander V. Chernikov 5992e324d29SAlexander V. Chernikov static void 6002e324d29SAlexander V. Chernikov tei_to_sockaddr_ent(struct tentry_info *tei, struct sockaddr *sa, 6012e324d29SAlexander V. Chernikov struct sockaddr *ma, int *set_mask) 6022e324d29SAlexander V. Chernikov { 6032e324d29SAlexander V. Chernikov int mlen; 6049fe15d06SAlexander V. Chernikov #ifdef INET 6052e324d29SAlexander V. Chernikov struct sockaddr_in *addr, *mask; 6069fe15d06SAlexander V. Chernikov #endif 6079fe15d06SAlexander V. Chernikov #ifdef INET6 608720ee730SAlexander V. Chernikov struct sa_in6 *addr6, *mask6; 6099fe15d06SAlexander V. Chernikov #endif 6102e324d29SAlexander V. Chernikov in_addr_t a4; 6112e324d29SAlexander V. Chernikov 6122e324d29SAlexander V. Chernikov mlen = tei->masklen; 6132e324d29SAlexander V. Chernikov 6142e324d29SAlexander V. Chernikov if (tei->subtype == AF_INET) { 6152e324d29SAlexander V. Chernikov #ifdef INET 6162e324d29SAlexander V. Chernikov addr = (struct sockaddr_in *)sa; 6172e324d29SAlexander V. Chernikov mask = (struct sockaddr_in *)ma; 6182e324d29SAlexander V. Chernikov /* Set 'total' structure length */ 6192e324d29SAlexander V. Chernikov KEY_LEN(*addr) = KEY_LEN_INET; 6202e324d29SAlexander V. Chernikov KEY_LEN(*mask) = KEY_LEN_INET; 6212e324d29SAlexander V. Chernikov addr->sin_family = AF_INET; 6222e324d29SAlexander V. Chernikov mask->sin_addr.s_addr = 6232e324d29SAlexander V. Chernikov htonl(mlen ? ~((1 << (32 - mlen)) - 1) : 0); 6242e324d29SAlexander V. Chernikov a4 = *((in_addr_t *)tei->paddr); 6252e324d29SAlexander V. Chernikov addr->sin_addr.s_addr = a4 & mask->sin_addr.s_addr; 6262e324d29SAlexander V. Chernikov if (mlen != 32) 6272e324d29SAlexander V. Chernikov *set_mask = 1; 6282e324d29SAlexander V. Chernikov else 6292e324d29SAlexander V. Chernikov *set_mask = 0; 6302e324d29SAlexander V. Chernikov #endif 6312e324d29SAlexander V. Chernikov #ifdef INET6 6322e324d29SAlexander V. Chernikov } else if (tei->subtype == AF_INET6) { 6332e324d29SAlexander V. Chernikov /* IPv6 case */ 634720ee730SAlexander V. Chernikov addr6 = (struct sa_in6 *)sa; 635720ee730SAlexander V. Chernikov mask6 = (struct sa_in6 *)ma; 6362e324d29SAlexander V. Chernikov /* Set 'total' structure length */ 6372e324d29SAlexander V. Chernikov KEY_LEN(*addr6) = KEY_LEN_INET6; 6382e324d29SAlexander V. Chernikov KEY_LEN(*mask6) = KEY_LEN_INET6; 6392e324d29SAlexander V. Chernikov addr6->sin6_family = AF_INET6; 6402e324d29SAlexander V. Chernikov ipv6_writemask(&mask6->sin6_addr, mlen); 6412e324d29SAlexander V. Chernikov memcpy(&addr6->sin6_addr, tei->paddr, sizeof(struct in6_addr)); 6422e324d29SAlexander V. Chernikov APPLY_MASK(&addr6->sin6_addr, &mask6->sin6_addr); 6432e324d29SAlexander V. Chernikov if (mlen != 128) 6442e324d29SAlexander V. Chernikov *set_mask = 1; 6452e324d29SAlexander V. Chernikov else 6462e324d29SAlexander V. Chernikov *set_mask = 0; 6472e324d29SAlexander V. Chernikov #endif 6482e324d29SAlexander V. Chernikov } 649d699ee2dSAlexander V. Chernikov } 6509f7d47b0SAlexander V. Chernikov 6519f7d47b0SAlexander V. Chernikov static int 652a399f8beSAlexander V. Chernikov ta_prepare_add_radix(struct ip_fw_chain *ch, struct tentry_info *tei, 65368394ec8SAlexander V. Chernikov void *ta_buf) 6549f7d47b0SAlexander V. Chernikov { 655c21034b7SAlexander V. Chernikov struct ta_buf_radix *tb; 656c21034b7SAlexander V. Chernikov struct radix_addr_entry *ent; 657d699ee2dSAlexander V. Chernikov #ifdef INET6 658c21034b7SAlexander V. Chernikov struct radix_addr_xentry *xent; 659d699ee2dSAlexander V. Chernikov #endif 6602e324d29SAlexander V. Chernikov struct sockaddr *addr, *mask; 6612e324d29SAlexander V. Chernikov int mlen, set_mask; 6629f7d47b0SAlexander V. Chernikov 663c21034b7SAlexander V. Chernikov tb = (struct ta_buf_radix *)ta_buf; 6649f7d47b0SAlexander V. Chernikov 6659f7d47b0SAlexander V. Chernikov mlen = tei->masklen; 6662e324d29SAlexander V. Chernikov set_mask = 0; 6679f7d47b0SAlexander V. Chernikov 668ac35ff17SAlexander V. Chernikov if (tei->subtype == AF_INET) { 6699f7d47b0SAlexander V. Chernikov #ifdef INET 6709f7d47b0SAlexander V. Chernikov if (mlen > 32) 6719f7d47b0SAlexander V. Chernikov return (EINVAL); 6729f7d47b0SAlexander V. Chernikov ent = malloc(sizeof(*ent), M_IPFW_TBL, M_WAITOK | M_ZERO); 673e0a8b9eeSAlexander V. Chernikov ent->masklen = mlen; 6742e324d29SAlexander V. Chernikov 6752e324d29SAlexander V. Chernikov addr = (struct sockaddr *)&ent->addr; 6762e324d29SAlexander V. Chernikov mask = (struct sockaddr *)&tb->addr.a4.ma; 6779f7d47b0SAlexander V. Chernikov tb->ent_ptr = ent; 6789f7d47b0SAlexander V. Chernikov #endif 6799f7d47b0SAlexander V. Chernikov #ifdef INET6 680ac35ff17SAlexander V. Chernikov } else if (tei->subtype == AF_INET6) { 6819f7d47b0SAlexander V. Chernikov /* IPv6 case */ 6829f7d47b0SAlexander V. Chernikov if (mlen > 128) 6839f7d47b0SAlexander V. Chernikov return (EINVAL); 6849f7d47b0SAlexander V. Chernikov xent = malloc(sizeof(*xent), M_IPFW_TBL, M_WAITOK | M_ZERO); 685e0a8b9eeSAlexander V. Chernikov xent->masklen = mlen; 6862e324d29SAlexander V. Chernikov 6872e324d29SAlexander V. Chernikov addr = (struct sockaddr *)&xent->addr6; 6882e324d29SAlexander V. Chernikov mask = (struct sockaddr *)&tb->addr.a6.ma; 6899f7d47b0SAlexander V. Chernikov tb->ent_ptr = xent; 6909f7d47b0SAlexander V. Chernikov #endif 6919f7d47b0SAlexander V. Chernikov } else { 6929f7d47b0SAlexander V. Chernikov /* Unknown CIDR type */ 6939f7d47b0SAlexander V. Chernikov return (EINVAL); 6949f7d47b0SAlexander V. Chernikov } 6959f7d47b0SAlexander V. Chernikov 6962e324d29SAlexander V. Chernikov tei_to_sockaddr_ent(tei, addr, mask, &set_mask); 6972e324d29SAlexander V. Chernikov /* Set pointers */ 6982e324d29SAlexander V. Chernikov tb->addr_ptr = addr; 6992e324d29SAlexander V. Chernikov if (set_mask != 0) 7002e324d29SAlexander V. Chernikov tb->mask_ptr = mask; 7012e324d29SAlexander V. Chernikov 7029f7d47b0SAlexander V. Chernikov return (0); 7039f7d47b0SAlexander V. Chernikov } 7049f7d47b0SAlexander V. Chernikov 7059f7d47b0SAlexander V. Chernikov static int 706a399f8beSAlexander V. Chernikov ta_add_radix(void *ta_state, struct table_info *ti, struct tentry_info *tei, 707b6ee846eSAlexander V. Chernikov void *ta_buf, uint32_t *pnum) 7089f7d47b0SAlexander V. Chernikov { 7095f379342SAlexander V. Chernikov struct radix_cfg *cfg; 7109f7d47b0SAlexander V. Chernikov struct radix_node_head *rnh; 7119f7d47b0SAlexander V. Chernikov struct radix_node *rn; 712c21034b7SAlexander V. Chernikov struct ta_buf_radix *tb; 713648e8380SAlexander V. Chernikov uint32_t *old_value, value; 7149f7d47b0SAlexander V. Chernikov 7155f379342SAlexander V. Chernikov cfg = (struct radix_cfg *)ta_state; 716c21034b7SAlexander V. Chernikov tb = (struct ta_buf_radix *)ta_buf; 7179f7d47b0SAlexander V. Chernikov 71813263632SAlexander V. Chernikov /* Save current entry value from @tei */ 71913263632SAlexander V. Chernikov if (tei->subtype == AF_INET) { 7209f7d47b0SAlexander V. Chernikov rnh = ti->state; 72113263632SAlexander V. Chernikov ((struct radix_addr_entry *)tb->ent_ptr)->value = tei->value; 72213263632SAlexander V. Chernikov } else { 7239f7d47b0SAlexander V. Chernikov rnh = ti->xstate; 72413263632SAlexander V. Chernikov ((struct radix_addr_xentry *)tb->ent_ptr)->value = tei->value; 72513263632SAlexander V. Chernikov } 7269f7d47b0SAlexander V. Chernikov 7274c0c07a5SAlexander V. Chernikov /* Search for an entry first */ 72861eee0e2SAlexander V. Chernikov rn = rnh->rnh_lookup(tb->addr_ptr, tb->mask_ptr, &rnh->rh); 7294c0c07a5SAlexander V. Chernikov if (rn != NULL) { 730ac35ff17SAlexander V. Chernikov if ((tei->flags & TEI_FLAGS_UPDATE) == 0) 7319f7d47b0SAlexander V. Chernikov return (EEXIST); 732ac35ff17SAlexander V. Chernikov /* Record already exists. Update value if we're asked to */ 733648e8380SAlexander V. Chernikov if (tei->subtype == AF_INET) 734c21034b7SAlexander V. Chernikov old_value = &((struct radix_addr_entry *)rn)->value; 735648e8380SAlexander V. Chernikov else 736c21034b7SAlexander V. Chernikov old_value = &((struct radix_addr_xentry *)rn)->value; 737648e8380SAlexander V. Chernikov 738648e8380SAlexander V. Chernikov value = *old_value; 739648e8380SAlexander V. Chernikov *old_value = tei->value; 740648e8380SAlexander V. Chernikov tei->value = value; 741ac35ff17SAlexander V. Chernikov 742ac35ff17SAlexander V. Chernikov /* Indicate that update has happened instead of addition */ 743ac35ff17SAlexander V. Chernikov tei->flags |= TEI_FLAGS_UPDATED; 744adea6201SAlexander V. Chernikov *pnum = 0; 745e0a8b9eeSAlexander V. Chernikov 746e0a8b9eeSAlexander V. Chernikov return (0); 747ac35ff17SAlexander V. Chernikov } 748ac35ff17SAlexander V. Chernikov 7494c0c07a5SAlexander V. Chernikov if ((tei->flags & TEI_FLAGS_DONTADD) != 0) 7504c0c07a5SAlexander V. Chernikov return (EFBIG); 7514c0c07a5SAlexander V. Chernikov 75261eee0e2SAlexander V. Chernikov rn = rnh->rnh_addaddr(tb->addr_ptr, tb->mask_ptr, &rnh->rh,tb->ent_ptr); 7534c0c07a5SAlexander V. Chernikov if (rn == NULL) { 7544c0c07a5SAlexander V. Chernikov /* Unknown error */ 7554c0c07a5SAlexander V. Chernikov return (EINVAL); 7564c0c07a5SAlexander V. Chernikov } 7574c0c07a5SAlexander V. Chernikov 7585f379342SAlexander V. Chernikov if (tei->subtype == AF_INET) 7595f379342SAlexander V. Chernikov cfg->count4++; 7605f379342SAlexander V. Chernikov else 7615f379342SAlexander V. Chernikov cfg->count6++; 762ac35ff17SAlexander V. Chernikov tb->ent_ptr = NULL; 763adea6201SAlexander V. Chernikov *pnum = 1; 7649f7d47b0SAlexander V. Chernikov 7659f7d47b0SAlexander V. Chernikov return (0); 7669f7d47b0SAlexander V. Chernikov } 7679f7d47b0SAlexander V. Chernikov 7689f7d47b0SAlexander V. Chernikov static int 769a399f8beSAlexander V. Chernikov ta_prepare_del_radix(struct ip_fw_chain *ch, struct tentry_info *tei, 77068394ec8SAlexander V. Chernikov void *ta_buf) 7719f7d47b0SAlexander V. Chernikov { 772c21034b7SAlexander V. Chernikov struct ta_buf_radix *tb; 7732e324d29SAlexander V. Chernikov struct sockaddr *addr, *mask; 7742e324d29SAlexander V. Chernikov int mlen, set_mask; 7759f7d47b0SAlexander V. Chernikov 776c21034b7SAlexander V. Chernikov tb = (struct ta_buf_radix *)ta_buf; 7779f7d47b0SAlexander V. Chernikov 7789f7d47b0SAlexander V. Chernikov mlen = tei->masklen; 7792e324d29SAlexander V. Chernikov set_mask = 0; 7809f7d47b0SAlexander V. Chernikov 781ac35ff17SAlexander V. Chernikov if (tei->subtype == AF_INET) { 782e0a8b9eeSAlexander V. Chernikov if (mlen > 32) 783e0a8b9eeSAlexander V. Chernikov return (EINVAL); 7842e324d29SAlexander V. Chernikov 7852e324d29SAlexander V. Chernikov addr = (struct sockaddr *)&tb->addr.a4.sa; 7862e324d29SAlexander V. Chernikov mask = (struct sockaddr *)&tb->addr.a4.ma; 7879f7d47b0SAlexander V. Chernikov #ifdef INET6 788ac35ff17SAlexander V. Chernikov } else if (tei->subtype == AF_INET6) { 7899f7d47b0SAlexander V. Chernikov if (mlen > 128) 7909f7d47b0SAlexander V. Chernikov return (EINVAL); 7912e324d29SAlexander V. Chernikov 7922e324d29SAlexander V. Chernikov addr = (struct sockaddr *)&tb->addr.a6.sa; 7932e324d29SAlexander V. Chernikov mask = (struct sockaddr *)&tb->addr.a6.ma; 7949f7d47b0SAlexander V. Chernikov #endif 7959f7d47b0SAlexander V. Chernikov } else 7969f7d47b0SAlexander V. Chernikov return (EINVAL); 7979f7d47b0SAlexander V. Chernikov 7982e324d29SAlexander V. Chernikov tei_to_sockaddr_ent(tei, addr, mask, &set_mask); 7992e324d29SAlexander V. Chernikov tb->addr_ptr = addr; 8002e324d29SAlexander V. Chernikov if (set_mask != 0) 8012e324d29SAlexander V. Chernikov tb->mask_ptr = mask; 8022e324d29SAlexander V. Chernikov 8039f7d47b0SAlexander V. Chernikov return (0); 8049f7d47b0SAlexander V. Chernikov } 8059f7d47b0SAlexander V. Chernikov 8069f7d47b0SAlexander V. Chernikov static int 807a399f8beSAlexander V. Chernikov ta_del_radix(void *ta_state, struct table_info *ti, struct tentry_info *tei, 808b6ee846eSAlexander V. Chernikov void *ta_buf, uint32_t *pnum) 8099f7d47b0SAlexander V. Chernikov { 8105f379342SAlexander V. Chernikov struct radix_cfg *cfg; 8119f7d47b0SAlexander V. Chernikov struct radix_node_head *rnh; 8129f7d47b0SAlexander V. Chernikov struct radix_node *rn; 813c21034b7SAlexander V. Chernikov struct ta_buf_radix *tb; 8149f7d47b0SAlexander V. Chernikov 8155f379342SAlexander V. Chernikov cfg = (struct radix_cfg *)ta_state; 816c21034b7SAlexander V. Chernikov tb = (struct ta_buf_radix *)ta_buf; 8179f7d47b0SAlexander V. Chernikov 818ac35ff17SAlexander V. Chernikov if (tei->subtype == AF_INET) 8199f7d47b0SAlexander V. Chernikov rnh = ti->state; 8209f7d47b0SAlexander V. Chernikov else 8219f7d47b0SAlexander V. Chernikov rnh = ti->xstate; 8229f7d47b0SAlexander V. Chernikov 82361eee0e2SAlexander V. Chernikov rn = rnh->rnh_deladdr(tb->addr_ptr, tb->mask_ptr, &rnh->rh); 8249f7d47b0SAlexander V. Chernikov 8253a845e10SAlexander V. Chernikov if (rn == NULL) 8263a845e10SAlexander V. Chernikov return (ENOENT); 8273a845e10SAlexander V. Chernikov 828648e8380SAlexander V. Chernikov /* Save entry value to @tei */ 829648e8380SAlexander V. Chernikov if (tei->subtype == AF_INET) 830c21034b7SAlexander V. Chernikov tei->value = ((struct radix_addr_entry *)rn)->value; 831648e8380SAlexander V. Chernikov else 832c21034b7SAlexander V. Chernikov tei->value = ((struct radix_addr_xentry *)rn)->value; 833648e8380SAlexander V. Chernikov 8349f7d47b0SAlexander V. Chernikov tb->ent_ptr = rn; 8359f7d47b0SAlexander V. Chernikov 8365f379342SAlexander V. Chernikov if (tei->subtype == AF_INET) 8375f379342SAlexander V. Chernikov cfg->count4--; 8385f379342SAlexander V. Chernikov else 8395f379342SAlexander V. Chernikov cfg->count6--; 840adea6201SAlexander V. Chernikov *pnum = 1; 841adea6201SAlexander V. Chernikov 8429f7d47b0SAlexander V. Chernikov return (0); 8439f7d47b0SAlexander V. Chernikov } 8449f7d47b0SAlexander V. Chernikov 8459f7d47b0SAlexander V. Chernikov static void 846a399f8beSAlexander V. Chernikov ta_flush_radix_entry(struct ip_fw_chain *ch, struct tentry_info *tei, 84768394ec8SAlexander V. Chernikov void *ta_buf) 8489f7d47b0SAlexander V. Chernikov { 849c21034b7SAlexander V. Chernikov struct ta_buf_radix *tb; 8509f7d47b0SAlexander V. Chernikov 851c21034b7SAlexander V. Chernikov tb = (struct ta_buf_radix *)ta_buf; 8529f7d47b0SAlexander V. Chernikov 853ac35ff17SAlexander V. Chernikov if (tb->ent_ptr != NULL) 8549f7d47b0SAlexander V. Chernikov free(tb->ent_ptr, M_IPFW_TBL); 8559f7d47b0SAlexander V. Chernikov } 8569f7d47b0SAlexander V. Chernikov 857b6ee846eSAlexander V. Chernikov static int 858301290bcSAlexander V. Chernikov ta_need_modify_radix(void *ta_state, struct table_info *ti, uint32_t count, 859b6ee846eSAlexander V. Chernikov uint64_t *pflags) 860b6ee846eSAlexander V. Chernikov { 861b6ee846eSAlexander V. Chernikov 862b6ee846eSAlexander V. Chernikov /* 8630bce0c23SAlexander V. Chernikov * radix does not require additional memory allocations 864b6ee846eSAlexander V. Chernikov * other than nodes itself. Adding new masks to the tree do 865b6ee846eSAlexander V. Chernikov * but we don't have any API to call (and we don't known which 866b6ee846eSAlexander V. Chernikov * sizes do we need). 867b6ee846eSAlexander V. Chernikov */ 868301290bcSAlexander V. Chernikov return (0); 869b6ee846eSAlexander V. Chernikov } 870b6ee846eSAlexander V. Chernikov 871c21034b7SAlexander V. Chernikov struct table_algo addr_radix = { 872c21034b7SAlexander V. Chernikov .name = "addr:radix", 873c21034b7SAlexander V. Chernikov .type = IPFW_TABLE_ADDR, 87457a1cf95SAlexander V. Chernikov .flags = TA_FLAG_DEFAULT, 875c21034b7SAlexander V. Chernikov .ta_buf_size = sizeof(struct ta_buf_radix), 8769f7d47b0SAlexander V. Chernikov .init = ta_init_radix, 8779f7d47b0SAlexander V. Chernikov .destroy = ta_destroy_radix, 878a399f8beSAlexander V. Chernikov .prepare_add = ta_prepare_add_radix, 879a399f8beSAlexander V. Chernikov .prepare_del = ta_prepare_del_radix, 880a399f8beSAlexander V. Chernikov .add = ta_add_radix, 881a399f8beSAlexander V. Chernikov .del = ta_del_radix, 882a399f8beSAlexander V. Chernikov .flush_entry = ta_flush_radix_entry, 8839f7d47b0SAlexander V. Chernikov .foreach = ta_foreach_radix, 88481d3153dSAlexander V. Chernikov .dump_tentry = ta_dump_radix_tentry, 88581d3153dSAlexander V. Chernikov .find_tentry = ta_find_radix_tentry, 8865f379342SAlexander V. Chernikov .dump_tinfo = ta_dump_radix_tinfo, 887301290bcSAlexander V. Chernikov .need_modify = ta_need_modify_radix, 8889f7d47b0SAlexander V. Chernikov }; 8899f7d47b0SAlexander V. Chernikov 8909f7d47b0SAlexander V. Chernikov 8919f7d47b0SAlexander V. Chernikov /* 892c21034b7SAlexander V. Chernikov * addr:hash cmds 89374b941f0SAlexander V. Chernikov * 89474b941f0SAlexander V. Chernikov * 89574b941f0SAlexander V. Chernikov * ti->data: 89674b941f0SAlexander V. Chernikov * [inv.mask4][inv.mask6][log2hsize4][log2hsize6] 89774b941f0SAlexander V. Chernikov * [ 8][ 8[ 8][ 8] 89874b941f0SAlexander V. Chernikov * 89974b941f0SAlexander V. Chernikov * inv.mask4: 32 - mask 90074b941f0SAlexander V. Chernikov * inv.mask6: 90174b941f0SAlexander V. Chernikov * 1) _slow lookup: mask 90274b941f0SAlexander V. Chernikov * 2) _aligned: (128 - mask) / 8 90374b941f0SAlexander V. Chernikov * 3) _64: 8 904ce2817b5SAlexander V. Chernikov * 905ce2817b5SAlexander V. Chernikov * 906ce2817b5SAlexander V. Chernikov * pflags: 907ce2817b5SAlexander V. Chernikov * [v4=1/v6=0][hsize] 908ce2817b5SAlexander V. Chernikov * [ 32][ 32] 90974b941f0SAlexander V. Chernikov */ 91074b941f0SAlexander V. Chernikov 91174b941f0SAlexander V. Chernikov struct chashentry; 91274b941f0SAlexander V. Chernikov 91374b941f0SAlexander V. Chernikov SLIST_HEAD(chashbhead, chashentry); 91474b941f0SAlexander V. Chernikov 91574b941f0SAlexander V. Chernikov struct chash_cfg { 91674b941f0SAlexander V. Chernikov struct chashbhead *head4; 91774b941f0SAlexander V. Chernikov struct chashbhead *head6; 91874b941f0SAlexander V. Chernikov size_t size4; 91974b941f0SAlexander V. Chernikov size_t size6; 920ce2817b5SAlexander V. Chernikov size_t items4; 921ce2817b5SAlexander V. Chernikov size_t items6; 92274b941f0SAlexander V. Chernikov uint8_t mask4; 92374b941f0SAlexander V. Chernikov uint8_t mask6; 92474b941f0SAlexander V. Chernikov }; 92574b941f0SAlexander V. Chernikov 92674b941f0SAlexander V. Chernikov struct chashentry { 92774b941f0SAlexander V. Chernikov SLIST_ENTRY(chashentry) next; 92874b941f0SAlexander V. Chernikov uint32_t value; 92974b941f0SAlexander V. Chernikov uint32_t type; 93074b941f0SAlexander V. Chernikov union { 93174b941f0SAlexander V. Chernikov uint32_t a4; /* Host format */ 93274b941f0SAlexander V. Chernikov struct in6_addr a6; /* Network format */ 93374b941f0SAlexander V. Chernikov } a; 93474b941f0SAlexander V. Chernikov }; 93574b941f0SAlexander V. Chernikov 9360bce0c23SAlexander V. Chernikov struct ta_buf_chash 9370bce0c23SAlexander V. Chernikov { 9380bce0c23SAlexander V. Chernikov void *ent_ptr; 9390bce0c23SAlexander V. Chernikov struct chashentry ent; 9400bce0c23SAlexander V. Chernikov }; 9410bce0c23SAlexander V. Chernikov 942d699ee2dSAlexander V. Chernikov #ifdef INET 9439fe15d06SAlexander V. Chernikov static __inline uint32_t hash_ip(uint32_t addr, int hsize); 944d699ee2dSAlexander V. Chernikov #endif 945d699ee2dSAlexander V. Chernikov #ifdef INET6 9469fe15d06SAlexander V. Chernikov static __inline uint32_t hash_ip6(struct in6_addr *addr6, int hsize); 9479fe15d06SAlexander V. Chernikov static __inline uint16_t hash_ip64(struct in6_addr *addr6, int hsize); 9489fe15d06SAlexander V. Chernikov static __inline uint32_t hash_ip6_slow(struct in6_addr *addr6, void *key, 9499fe15d06SAlexander V. Chernikov int mask, int hsize); 9509fe15d06SAlexander V. Chernikov static __inline uint32_t hash_ip6_al(struct in6_addr *addr6, void *key, int mask, 9519fe15d06SAlexander V. Chernikov int hsize); 952d699ee2dSAlexander V. Chernikov #endif 9539fe15d06SAlexander V. Chernikov static int ta_lookup_chash_slow(struct table_info *ti, void *key, uint32_t keylen, 9549fe15d06SAlexander V. Chernikov uint32_t *val); 9559fe15d06SAlexander V. Chernikov static int ta_lookup_chash_aligned(struct table_info *ti, void *key, 9569fe15d06SAlexander V. Chernikov uint32_t keylen, uint32_t *val); 9579fe15d06SAlexander V. Chernikov static int ta_lookup_chash_64(struct table_info *ti, void *key, uint32_t keylen, 9589fe15d06SAlexander V. Chernikov uint32_t *val); 9599fe15d06SAlexander V. Chernikov static int chash_parse_opts(struct chash_cfg *cfg, char *data); 9609fe15d06SAlexander V. Chernikov static void ta_print_chash_config(void *ta_state, struct table_info *ti, 9619fe15d06SAlexander V. Chernikov char *buf, size_t bufsize); 9629e3a53fdSAlexander V. Chernikov static int ta_log2(uint32_t v); 9639fe15d06SAlexander V. Chernikov static int ta_init_chash(struct ip_fw_chain *ch, void **ta_state, 9649fe15d06SAlexander V. Chernikov struct table_info *ti, char *data, uint8_t tflags); 9659fe15d06SAlexander V. Chernikov static void ta_destroy_chash(void *ta_state, struct table_info *ti); 9669fe15d06SAlexander V. Chernikov static void ta_dump_chash_tinfo(void *ta_state, struct table_info *ti, 9679fe15d06SAlexander V. Chernikov ipfw_ta_tinfo *tinfo); 9689fe15d06SAlexander V. Chernikov static int ta_dump_chash_tentry(void *ta_state, struct table_info *ti, 9699fe15d06SAlexander V. Chernikov void *e, ipfw_obj_tentry *tent); 9709fe15d06SAlexander V. Chernikov static uint32_t hash_ent(struct chashentry *ent, int af, int mlen, 9719fe15d06SAlexander V. Chernikov uint32_t size); 9729fe15d06SAlexander V. Chernikov static int tei_to_chash_ent(struct tentry_info *tei, struct chashentry *ent); 9739fe15d06SAlexander V. Chernikov static int ta_find_chash_tentry(void *ta_state, struct table_info *ti, 9749fe15d06SAlexander V. Chernikov ipfw_obj_tentry *tent); 9759fe15d06SAlexander V. Chernikov static void ta_foreach_chash(void *ta_state, struct table_info *ti, 9769fe15d06SAlexander V. Chernikov ta_foreach_f *f, void *arg); 9779fe15d06SAlexander V. Chernikov static int ta_prepare_add_chash(struct ip_fw_chain *ch, struct tentry_info *tei, 9789fe15d06SAlexander V. Chernikov void *ta_buf); 9799fe15d06SAlexander V. Chernikov static int ta_add_chash(void *ta_state, struct table_info *ti, 9809fe15d06SAlexander V. Chernikov struct tentry_info *tei, void *ta_buf, uint32_t *pnum); 9819fe15d06SAlexander V. Chernikov static int ta_prepare_del_chash(struct ip_fw_chain *ch, struct tentry_info *tei, 9829fe15d06SAlexander V. Chernikov void *ta_buf); 9839fe15d06SAlexander V. Chernikov static int ta_del_chash(void *ta_state, struct table_info *ti, 9849fe15d06SAlexander V. Chernikov struct tentry_info *tei, void *ta_buf, uint32_t *pnum); 9859fe15d06SAlexander V. Chernikov static void ta_flush_chash_entry(struct ip_fw_chain *ch, struct tentry_info *tei, 9869fe15d06SAlexander V. Chernikov void *ta_buf); 9879fe15d06SAlexander V. Chernikov static int ta_need_modify_chash(void *ta_state, struct table_info *ti, 9889fe15d06SAlexander V. Chernikov uint32_t count, uint64_t *pflags); 9899fe15d06SAlexander V. Chernikov static int ta_prepare_mod_chash(void *ta_buf, uint64_t *pflags); 9909fe15d06SAlexander V. Chernikov static int ta_fill_mod_chash(void *ta_state, struct table_info *ti, void *ta_buf, 9919fe15d06SAlexander V. Chernikov uint64_t *pflags); 9929fe15d06SAlexander V. Chernikov static void ta_modify_chash(void *ta_state, struct table_info *ti, void *ta_buf, 9939fe15d06SAlexander V. Chernikov uint64_t pflags); 9949fe15d06SAlexander V. Chernikov static void ta_flush_mod_chash(void *ta_buf); 9959fe15d06SAlexander V. Chernikov 9960bce0c23SAlexander V. Chernikov 997d699ee2dSAlexander V. Chernikov #ifdef INET 99874b941f0SAlexander V. Chernikov static __inline uint32_t 99974b941f0SAlexander V. Chernikov hash_ip(uint32_t addr, int hsize) 100074b941f0SAlexander V. Chernikov { 100174b941f0SAlexander V. Chernikov 100274b941f0SAlexander V. Chernikov return (addr % (hsize - 1)); 100374b941f0SAlexander V. Chernikov } 1004d699ee2dSAlexander V. Chernikov #endif 100574b941f0SAlexander V. Chernikov 1006d699ee2dSAlexander V. Chernikov #ifdef INET6 100774b941f0SAlexander V. Chernikov static __inline uint32_t 100874b941f0SAlexander V. Chernikov hash_ip6(struct in6_addr *addr6, int hsize) 100974b941f0SAlexander V. Chernikov { 101074b941f0SAlexander V. Chernikov uint32_t i; 101174b941f0SAlexander V. Chernikov 101274b941f0SAlexander V. Chernikov i = addr6->s6_addr32[0] ^ addr6->s6_addr32[1] ^ 101374b941f0SAlexander V. Chernikov addr6->s6_addr32[2] ^ addr6->s6_addr32[3]; 101474b941f0SAlexander V. Chernikov 101574b941f0SAlexander V. Chernikov return (i % (hsize - 1)); 101674b941f0SAlexander V. Chernikov } 101774b941f0SAlexander V. Chernikov 101874b941f0SAlexander V. Chernikov 101974b941f0SAlexander V. Chernikov static __inline uint16_t 102074b941f0SAlexander V. Chernikov hash_ip64(struct in6_addr *addr6, int hsize) 102174b941f0SAlexander V. Chernikov { 102274b941f0SAlexander V. Chernikov uint32_t i; 102374b941f0SAlexander V. Chernikov 102474b941f0SAlexander V. Chernikov i = addr6->s6_addr32[0] ^ addr6->s6_addr32[1]; 102574b941f0SAlexander V. Chernikov 102674b941f0SAlexander V. Chernikov return (i % (hsize - 1)); 102774b941f0SAlexander V. Chernikov } 102874b941f0SAlexander V. Chernikov 102974b941f0SAlexander V. Chernikov 103074b941f0SAlexander V. Chernikov static __inline uint32_t 103174b941f0SAlexander V. Chernikov hash_ip6_slow(struct in6_addr *addr6, void *key, int mask, int hsize) 103274b941f0SAlexander V. Chernikov { 103374b941f0SAlexander V. Chernikov struct in6_addr mask6; 103474b941f0SAlexander V. Chernikov 103574b941f0SAlexander V. Chernikov ipv6_writemask(&mask6, mask); 103674b941f0SAlexander V. Chernikov memcpy(addr6, key, sizeof(struct in6_addr)); 103774b941f0SAlexander V. Chernikov APPLY_MASK(addr6, &mask6); 103874b941f0SAlexander V. Chernikov return (hash_ip6(addr6, hsize)); 103974b941f0SAlexander V. Chernikov } 104074b941f0SAlexander V. Chernikov 104174b941f0SAlexander V. Chernikov static __inline uint32_t 104274b941f0SAlexander V. Chernikov hash_ip6_al(struct in6_addr *addr6, void *key, int mask, int hsize) 104374b941f0SAlexander V. Chernikov { 104474b941f0SAlexander V. Chernikov uint64_t *paddr; 104574b941f0SAlexander V. Chernikov 104674b941f0SAlexander V. Chernikov paddr = (uint64_t *)addr6; 104774b941f0SAlexander V. Chernikov *paddr = 0; 104874b941f0SAlexander V. Chernikov *(paddr + 1) = 0; 104974b941f0SAlexander V. Chernikov memcpy(addr6, key, mask); 105074b941f0SAlexander V. Chernikov return (hash_ip6(addr6, hsize)); 105174b941f0SAlexander V. Chernikov } 1052d699ee2dSAlexander V. Chernikov #endif 105374b941f0SAlexander V. Chernikov 105474b941f0SAlexander V. Chernikov static int 105574b941f0SAlexander V. Chernikov ta_lookup_chash_slow(struct table_info *ti, void *key, uint32_t keylen, 105674b941f0SAlexander V. Chernikov uint32_t *val) 105774b941f0SAlexander V. Chernikov { 105874b941f0SAlexander V. Chernikov struct chashbhead *head; 105974b941f0SAlexander V. Chernikov struct chashentry *ent; 106074b941f0SAlexander V. Chernikov uint16_t hash, hsize; 106174b941f0SAlexander V. Chernikov uint8_t imask; 106274b941f0SAlexander V. Chernikov 106374b941f0SAlexander V. Chernikov if (keylen == sizeof(in_addr_t)) { 1064d699ee2dSAlexander V. Chernikov #ifdef INET 106574b941f0SAlexander V. Chernikov head = (struct chashbhead *)ti->state; 106674b941f0SAlexander V. Chernikov imask = ti->data >> 24; 106774b941f0SAlexander V. Chernikov hsize = 1 << ((ti->data & 0xFFFF) >> 8); 106874b941f0SAlexander V. Chernikov uint32_t a; 106974b941f0SAlexander V. Chernikov a = ntohl(*((in_addr_t *)key)); 107074b941f0SAlexander V. Chernikov a = a >> imask; 107174b941f0SAlexander V. Chernikov hash = hash_ip(a, hsize); 107274b941f0SAlexander V. Chernikov SLIST_FOREACH(ent, &head[hash], next) { 107374b941f0SAlexander V. Chernikov if (ent->a.a4 == a) { 107474b941f0SAlexander V. Chernikov *val = ent->value; 107574b941f0SAlexander V. Chernikov return (1); 107674b941f0SAlexander V. Chernikov } 107774b941f0SAlexander V. Chernikov } 1078d699ee2dSAlexander V. Chernikov #endif 107974b941f0SAlexander V. Chernikov } else { 1080d699ee2dSAlexander V. Chernikov #ifdef INET6 108174b941f0SAlexander V. Chernikov /* IPv6: worst scenario: non-round mask */ 108274b941f0SAlexander V. Chernikov struct in6_addr addr6; 108374b941f0SAlexander V. Chernikov head = (struct chashbhead *)ti->xstate; 108474b941f0SAlexander V. Chernikov imask = (ti->data & 0xFF0000) >> 16; 108574b941f0SAlexander V. Chernikov hsize = 1 << (ti->data & 0xFF); 108674b941f0SAlexander V. Chernikov hash = hash_ip6_slow(&addr6, key, imask, hsize); 108774b941f0SAlexander V. Chernikov SLIST_FOREACH(ent, &head[hash], next) { 108874b941f0SAlexander V. Chernikov if (memcmp(&ent->a.a6, &addr6, 16) == 0) { 108974b941f0SAlexander V. Chernikov *val = ent->value; 109074b941f0SAlexander V. Chernikov return (1); 109174b941f0SAlexander V. Chernikov } 109274b941f0SAlexander V. Chernikov } 1093d699ee2dSAlexander V. Chernikov #endif 109474b941f0SAlexander V. Chernikov } 109574b941f0SAlexander V. Chernikov 109674b941f0SAlexander V. Chernikov return (0); 109774b941f0SAlexander V. Chernikov } 109874b941f0SAlexander V. Chernikov 109974b941f0SAlexander V. Chernikov static int 110074b941f0SAlexander V. Chernikov ta_lookup_chash_aligned(struct table_info *ti, void *key, uint32_t keylen, 110174b941f0SAlexander V. Chernikov uint32_t *val) 110274b941f0SAlexander V. Chernikov { 110374b941f0SAlexander V. Chernikov struct chashbhead *head; 110474b941f0SAlexander V. Chernikov struct chashentry *ent; 110574b941f0SAlexander V. Chernikov uint16_t hash, hsize; 110674b941f0SAlexander V. Chernikov uint8_t imask; 110774b941f0SAlexander V. Chernikov 110874b941f0SAlexander V. Chernikov if (keylen == sizeof(in_addr_t)) { 1109d699ee2dSAlexander V. Chernikov #ifdef INET 111074b941f0SAlexander V. Chernikov head = (struct chashbhead *)ti->state; 111174b941f0SAlexander V. Chernikov imask = ti->data >> 24; 111274b941f0SAlexander V. Chernikov hsize = 1 << ((ti->data & 0xFFFF) >> 8); 111374b941f0SAlexander V. Chernikov uint32_t a; 111474b941f0SAlexander V. Chernikov a = ntohl(*((in_addr_t *)key)); 111574b941f0SAlexander V. Chernikov a = a >> imask; 111674b941f0SAlexander V. Chernikov hash = hash_ip(a, hsize); 111774b941f0SAlexander V. Chernikov SLIST_FOREACH(ent, &head[hash], next) { 111874b941f0SAlexander V. Chernikov if (ent->a.a4 == a) { 111974b941f0SAlexander V. Chernikov *val = ent->value; 112074b941f0SAlexander V. Chernikov return (1); 112174b941f0SAlexander V. Chernikov } 112274b941f0SAlexander V. Chernikov } 1123d699ee2dSAlexander V. Chernikov #endif 112474b941f0SAlexander V. Chernikov } else { 1125d699ee2dSAlexander V. Chernikov #ifdef INET6 112674b941f0SAlexander V. Chernikov /* IPv6: aligned to 8bit mask */ 112774b941f0SAlexander V. Chernikov struct in6_addr addr6; 112874b941f0SAlexander V. Chernikov uint64_t *paddr, *ptmp; 112974b941f0SAlexander V. Chernikov head = (struct chashbhead *)ti->xstate; 113074b941f0SAlexander V. Chernikov imask = (ti->data & 0xFF0000) >> 16; 113174b941f0SAlexander V. Chernikov hsize = 1 << (ti->data & 0xFF); 113274b941f0SAlexander V. Chernikov 113374b941f0SAlexander V. Chernikov hash = hash_ip6_al(&addr6, key, imask, hsize); 113474b941f0SAlexander V. Chernikov paddr = (uint64_t *)&addr6; 113574b941f0SAlexander V. Chernikov SLIST_FOREACH(ent, &head[hash], next) { 113674b941f0SAlexander V. Chernikov ptmp = (uint64_t *)&ent->a.a6; 113774b941f0SAlexander V. Chernikov if (paddr[0] == ptmp[0] && paddr[1] == ptmp[1]) { 113874b941f0SAlexander V. Chernikov *val = ent->value; 113974b941f0SAlexander V. Chernikov return (1); 114074b941f0SAlexander V. Chernikov } 114174b941f0SAlexander V. Chernikov } 1142d699ee2dSAlexander V. Chernikov #endif 114374b941f0SAlexander V. Chernikov } 114474b941f0SAlexander V. Chernikov 114574b941f0SAlexander V. Chernikov return (0); 114674b941f0SAlexander V. Chernikov } 114774b941f0SAlexander V. Chernikov 114874b941f0SAlexander V. Chernikov static int 114974b941f0SAlexander V. Chernikov ta_lookup_chash_64(struct table_info *ti, void *key, uint32_t keylen, 115074b941f0SAlexander V. Chernikov uint32_t *val) 115174b941f0SAlexander V. Chernikov { 115274b941f0SAlexander V. Chernikov struct chashbhead *head; 115374b941f0SAlexander V. Chernikov struct chashentry *ent; 115474b941f0SAlexander V. Chernikov uint16_t hash, hsize; 115574b941f0SAlexander V. Chernikov uint8_t imask; 115674b941f0SAlexander V. Chernikov 115774b941f0SAlexander V. Chernikov if (keylen == sizeof(in_addr_t)) { 1158d699ee2dSAlexander V. Chernikov #ifdef INET 115974b941f0SAlexander V. Chernikov head = (struct chashbhead *)ti->state; 116074b941f0SAlexander V. Chernikov imask = ti->data >> 24; 116174b941f0SAlexander V. Chernikov hsize = 1 << ((ti->data & 0xFFFF) >> 8); 116274b941f0SAlexander V. Chernikov uint32_t a; 116374b941f0SAlexander V. Chernikov a = ntohl(*((in_addr_t *)key)); 116474b941f0SAlexander V. Chernikov a = a >> imask; 116574b941f0SAlexander V. Chernikov hash = hash_ip(a, hsize); 116674b941f0SAlexander V. Chernikov SLIST_FOREACH(ent, &head[hash], next) { 116774b941f0SAlexander V. Chernikov if (ent->a.a4 == a) { 116874b941f0SAlexander V. Chernikov *val = ent->value; 116974b941f0SAlexander V. Chernikov return (1); 117074b941f0SAlexander V. Chernikov } 117174b941f0SAlexander V. Chernikov } 1172d699ee2dSAlexander V. Chernikov #endif 117374b941f0SAlexander V. Chernikov } else { 1174d699ee2dSAlexander V. Chernikov #ifdef INET6 117574b941f0SAlexander V. Chernikov /* IPv6: /64 */ 117674b941f0SAlexander V. Chernikov uint64_t a6, *paddr; 117774b941f0SAlexander V. Chernikov head = (struct chashbhead *)ti->xstate; 117874b941f0SAlexander V. Chernikov paddr = (uint64_t *)key; 117974b941f0SAlexander V. Chernikov hsize = 1 << (ti->data & 0xFF); 118074b941f0SAlexander V. Chernikov a6 = *paddr; 118174b941f0SAlexander V. Chernikov hash = hash_ip64((struct in6_addr *)key, hsize); 118274b941f0SAlexander V. Chernikov SLIST_FOREACH(ent, &head[hash], next) { 118374b941f0SAlexander V. Chernikov paddr = (uint64_t *)&ent->a.a6; 118474b941f0SAlexander V. Chernikov if (a6 == *paddr) { 118574b941f0SAlexander V. Chernikov *val = ent->value; 118674b941f0SAlexander V. Chernikov return (1); 118774b941f0SAlexander V. Chernikov } 118874b941f0SAlexander V. Chernikov } 1189d699ee2dSAlexander V. Chernikov #endif 119074b941f0SAlexander V. Chernikov } 119174b941f0SAlexander V. Chernikov 119274b941f0SAlexander V. Chernikov return (0); 119374b941f0SAlexander V. Chernikov } 119474b941f0SAlexander V. Chernikov 119574b941f0SAlexander V. Chernikov static int 11960bce0c23SAlexander V. Chernikov chash_parse_opts(struct chash_cfg *cfg, char *data) 119774b941f0SAlexander V. Chernikov { 119874b941f0SAlexander V. Chernikov char *pdel, *pend, *s; 119974b941f0SAlexander V. Chernikov int mask4, mask6; 120074b941f0SAlexander V. Chernikov 12010bce0c23SAlexander V. Chernikov mask4 = cfg->mask4; 12020bce0c23SAlexander V. Chernikov mask6 = cfg->mask6; 120374b941f0SAlexander V. Chernikov 120474b941f0SAlexander V. Chernikov if (data == NULL) 120574b941f0SAlexander V. Chernikov return (0); 120674b941f0SAlexander V. Chernikov if ((pdel = strchr(data, ' ')) == NULL) 120774b941f0SAlexander V. Chernikov return (0); 120874b941f0SAlexander V. Chernikov while (*pdel == ' ') 120974b941f0SAlexander V. Chernikov pdel++; 121074b941f0SAlexander V. Chernikov if (strncmp(pdel, "masks=", 6) != 0) 121174b941f0SAlexander V. Chernikov return (EINVAL); 121274b941f0SAlexander V. Chernikov if ((s = strchr(pdel, ' ')) != NULL) 121374b941f0SAlexander V. Chernikov *s++ = '\0'; 121474b941f0SAlexander V. Chernikov 121574b941f0SAlexander V. Chernikov pdel += 6; 121674b941f0SAlexander V. Chernikov /* Need /XX[,/YY] */ 121774b941f0SAlexander V. Chernikov if (*pdel++ != '/') 121874b941f0SAlexander V. Chernikov return (EINVAL); 121974b941f0SAlexander V. Chernikov mask4 = strtol(pdel, &pend, 10); 122074b941f0SAlexander V. Chernikov if (*pend == ',') { 122174b941f0SAlexander V. Chernikov /* ,/YY */ 122274b941f0SAlexander V. Chernikov pdel = pend + 1; 122374b941f0SAlexander V. Chernikov if (*pdel++ != '/') 122474b941f0SAlexander V. Chernikov return (EINVAL); 122574b941f0SAlexander V. Chernikov mask6 = strtol(pdel, &pend, 10); 122674b941f0SAlexander V. Chernikov if (*pend != '\0') 122774b941f0SAlexander V. Chernikov return (EINVAL); 122874b941f0SAlexander V. Chernikov } else if (*pend != '\0') 122974b941f0SAlexander V. Chernikov return (EINVAL); 123074b941f0SAlexander V. Chernikov 123174b941f0SAlexander V. Chernikov if (mask4 < 0 || mask4 > 32 || mask6 < 0 || mask6 > 128) 123274b941f0SAlexander V. Chernikov return (EINVAL); 123374b941f0SAlexander V. Chernikov 12340bce0c23SAlexander V. Chernikov cfg->mask4 = mask4; 12350bce0c23SAlexander V. Chernikov cfg->mask6 = mask6; 123674b941f0SAlexander V. Chernikov 123774b941f0SAlexander V. Chernikov return (0); 123874b941f0SAlexander V. Chernikov } 123974b941f0SAlexander V. Chernikov 124074b941f0SAlexander V. Chernikov static void 124174b941f0SAlexander V. Chernikov ta_print_chash_config(void *ta_state, struct table_info *ti, char *buf, 124274b941f0SAlexander V. Chernikov size_t bufsize) 124374b941f0SAlexander V. Chernikov { 12440bce0c23SAlexander V. Chernikov struct chash_cfg *cfg; 124574b941f0SAlexander V. Chernikov 12460bce0c23SAlexander V. Chernikov cfg = (struct chash_cfg *)ta_state; 124774b941f0SAlexander V. Chernikov 12480bce0c23SAlexander V. Chernikov if (cfg->mask4 != 32 || cfg->mask6 != 128) 1249c21034b7SAlexander V. Chernikov snprintf(buf, bufsize, "%s masks=/%d,/%d", "addr:hash", 12500bce0c23SAlexander V. Chernikov cfg->mask4, cfg->mask6); 125174b941f0SAlexander V. Chernikov else 1252c21034b7SAlexander V. Chernikov snprintf(buf, bufsize, "%s", "addr:hash"); 125374b941f0SAlexander V. Chernikov } 125474b941f0SAlexander V. Chernikov 1255914bffb6SAlexander V. Chernikov static int 12569e3a53fdSAlexander V. Chernikov ta_log2(uint32_t v) 1257914bffb6SAlexander V. Chernikov { 1258914bffb6SAlexander V. Chernikov uint32_t r; 1259914bffb6SAlexander V. Chernikov 1260914bffb6SAlexander V. Chernikov r = 0; 1261914bffb6SAlexander V. Chernikov while (v >>= 1) 1262914bffb6SAlexander V. Chernikov r++; 1263914bffb6SAlexander V. Chernikov 1264914bffb6SAlexander V. Chernikov return (r); 1265914bffb6SAlexander V. Chernikov } 126674b941f0SAlexander V. Chernikov 126774b941f0SAlexander V. Chernikov /* 126874b941f0SAlexander V. Chernikov * New table. 126974b941f0SAlexander V. Chernikov * We assume 'data' to be either NULL or the following format: 1270c21034b7SAlexander V. Chernikov * 'addr:hash [masks=/32[,/128]]' 127174b941f0SAlexander V. Chernikov */ 127274b941f0SAlexander V. Chernikov static int 127374b941f0SAlexander V. Chernikov ta_init_chash(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti, 1274914bffb6SAlexander V. Chernikov char *data, uint8_t tflags) 127574b941f0SAlexander V. Chernikov { 127674b941f0SAlexander V. Chernikov int error, i; 1277914bffb6SAlexander V. Chernikov uint32_t hsize; 12780bce0c23SAlexander V. Chernikov struct chash_cfg *cfg; 127974b941f0SAlexander V. Chernikov 12800bce0c23SAlexander V. Chernikov cfg = malloc(sizeof(struct chash_cfg), M_IPFW, M_WAITOK | M_ZERO); 128174b941f0SAlexander V. Chernikov 12820bce0c23SAlexander V. Chernikov cfg->mask4 = 32; 12830bce0c23SAlexander V. Chernikov cfg->mask6 = 128; 128474b941f0SAlexander V. Chernikov 12850bce0c23SAlexander V. Chernikov if ((error = chash_parse_opts(cfg, data)) != 0) { 12860bce0c23SAlexander V. Chernikov free(cfg, M_IPFW); 128774b941f0SAlexander V. Chernikov return (error); 128874b941f0SAlexander V. Chernikov } 128974b941f0SAlexander V. Chernikov 12900bce0c23SAlexander V. Chernikov cfg->size4 = 128; 12910bce0c23SAlexander V. Chernikov cfg->size6 = 128; 129274b941f0SAlexander V. Chernikov 12930bce0c23SAlexander V. Chernikov cfg->head4 = malloc(sizeof(struct chashbhead) * cfg->size4, M_IPFW, 129474b941f0SAlexander V. Chernikov M_WAITOK | M_ZERO); 12950bce0c23SAlexander V. Chernikov cfg->head6 = malloc(sizeof(struct chashbhead) * cfg->size6, M_IPFW, 129674b941f0SAlexander V. Chernikov M_WAITOK | M_ZERO); 12970bce0c23SAlexander V. Chernikov for (i = 0; i < cfg->size4; i++) 12980bce0c23SAlexander V. Chernikov SLIST_INIT(&cfg->head4[i]); 12990bce0c23SAlexander V. Chernikov for (i = 0; i < cfg->size6; i++) 13000bce0c23SAlexander V. Chernikov SLIST_INIT(&cfg->head6[i]); 130174b941f0SAlexander V. Chernikov 130274b941f0SAlexander V. Chernikov 13030bce0c23SAlexander V. Chernikov *ta_state = cfg; 13040bce0c23SAlexander V. Chernikov ti->state = cfg->head4; 13050bce0c23SAlexander V. Chernikov ti->xstate = cfg->head6; 130674b941f0SAlexander V. Chernikov 130774b941f0SAlexander V. Chernikov /* Store data depending on v6 mask length */ 13089e3a53fdSAlexander V. Chernikov hsize = ta_log2(cfg->size4) << 8 | ta_log2(cfg->size6); 13090bce0c23SAlexander V. Chernikov if (cfg->mask6 == 64) { 13100bce0c23SAlexander V. Chernikov ti->data = (32 - cfg->mask4) << 24 | (128 - cfg->mask6) << 16| 1311914bffb6SAlexander V. Chernikov hsize; 131274b941f0SAlexander V. Chernikov ti->lookup = ta_lookup_chash_64; 13130bce0c23SAlexander V. Chernikov } else if ((cfg->mask6 % 8) == 0) { 13140bce0c23SAlexander V. Chernikov ti->data = (32 - cfg->mask4) << 24 | 13150bce0c23SAlexander V. Chernikov cfg->mask6 << 13 | hsize; 131674b941f0SAlexander V. Chernikov ti->lookup = ta_lookup_chash_aligned; 131774b941f0SAlexander V. Chernikov } else { 131874b941f0SAlexander V. Chernikov /* don't do that! */ 13190bce0c23SAlexander V. Chernikov ti->data = (32 - cfg->mask4) << 24 | 13200bce0c23SAlexander V. Chernikov cfg->mask6 << 16 | hsize; 132174b941f0SAlexander V. Chernikov ti->lookup = ta_lookup_chash_slow; 132274b941f0SAlexander V. Chernikov } 132374b941f0SAlexander V. Chernikov 132474b941f0SAlexander V. Chernikov return (0); 132574b941f0SAlexander V. Chernikov } 132674b941f0SAlexander V. Chernikov 132774b941f0SAlexander V. Chernikov static void 132874b941f0SAlexander V. Chernikov ta_destroy_chash(void *ta_state, struct table_info *ti) 132974b941f0SAlexander V. Chernikov { 13300bce0c23SAlexander V. Chernikov struct chash_cfg *cfg; 133174b941f0SAlexander V. Chernikov struct chashentry *ent, *ent_next; 133274b941f0SAlexander V. Chernikov int i; 133374b941f0SAlexander V. Chernikov 13340bce0c23SAlexander V. Chernikov cfg = (struct chash_cfg *)ta_state; 133574b941f0SAlexander V. Chernikov 13360bce0c23SAlexander V. Chernikov for (i = 0; i < cfg->size4; i++) 13370bce0c23SAlexander V. Chernikov SLIST_FOREACH_SAFE(ent, &cfg->head4[i], next, ent_next) 133874b941f0SAlexander V. Chernikov free(ent, M_IPFW_TBL); 133974b941f0SAlexander V. Chernikov 13400bce0c23SAlexander V. Chernikov for (i = 0; i < cfg->size6; i++) 13410bce0c23SAlexander V. Chernikov SLIST_FOREACH_SAFE(ent, &cfg->head6[i], next, ent_next) 134274b941f0SAlexander V. Chernikov free(ent, M_IPFW_TBL); 134374b941f0SAlexander V. Chernikov 13440bce0c23SAlexander V. Chernikov free(cfg->head4, M_IPFW); 13450bce0c23SAlexander V. Chernikov free(cfg->head6, M_IPFW); 1346ce2817b5SAlexander V. Chernikov 13470bce0c23SAlexander V. Chernikov free(cfg, M_IPFW); 134874b941f0SAlexander V. Chernikov } 134974b941f0SAlexander V. Chernikov 13505f379342SAlexander V. Chernikov static void 13515f379342SAlexander V. Chernikov ta_dump_chash_tinfo(void *ta_state, struct table_info *ti, ipfw_ta_tinfo *tinfo) 13525f379342SAlexander V. Chernikov { 13535f379342SAlexander V. Chernikov struct chash_cfg *cfg; 13545f379342SAlexander V. Chernikov 13555f379342SAlexander V. Chernikov cfg = (struct chash_cfg *)ta_state; 13565f379342SAlexander V. Chernikov 13575f379342SAlexander V. Chernikov tinfo->flags = IPFW_TATFLAGS_AFDATA | IPFW_TATFLAGS_AFITEM; 13585f379342SAlexander V. Chernikov tinfo->taclass4 = IPFW_TACLASS_HASH; 13595f379342SAlexander V. Chernikov tinfo->size4 = cfg->size4; 13605f379342SAlexander V. Chernikov tinfo->count4 = cfg->items4; 13615f379342SAlexander V. Chernikov tinfo->itemsize4 = sizeof(struct chashentry); 13625f379342SAlexander V. Chernikov tinfo->taclass6 = IPFW_TACLASS_HASH; 13635f379342SAlexander V. Chernikov tinfo->size6 = cfg->size6; 13645f379342SAlexander V. Chernikov tinfo->count6 = cfg->items6; 13655f379342SAlexander V. Chernikov tinfo->itemsize6 = sizeof(struct chashentry); 13665f379342SAlexander V. Chernikov } 13675f379342SAlexander V. Chernikov 136874b941f0SAlexander V. Chernikov static int 136974b941f0SAlexander V. Chernikov ta_dump_chash_tentry(void *ta_state, struct table_info *ti, void *e, 137074b941f0SAlexander V. Chernikov ipfw_obj_tentry *tent) 137174b941f0SAlexander V. Chernikov { 13720bce0c23SAlexander V. Chernikov struct chash_cfg *cfg; 137374b941f0SAlexander V. Chernikov struct chashentry *ent; 137474b941f0SAlexander V. Chernikov 13750bce0c23SAlexander V. Chernikov cfg = (struct chash_cfg *)ta_state; 137674b941f0SAlexander V. Chernikov ent = (struct chashentry *)e; 137774b941f0SAlexander V. Chernikov 137874b941f0SAlexander V. Chernikov if (ent->type == AF_INET) { 13790bce0c23SAlexander V. Chernikov tent->k.addr.s_addr = htonl(ent->a.a4 << (32 - cfg->mask4)); 13800bce0c23SAlexander V. Chernikov tent->masklen = cfg->mask4; 138174b941f0SAlexander V. Chernikov tent->subtype = AF_INET; 13820cba2b28SAlexander V. Chernikov tent->v.kidx = ent->value; 138374b941f0SAlexander V. Chernikov #ifdef INET6 138474b941f0SAlexander V. Chernikov } else { 1385ba3e1361SAndrey V. Elsukov memcpy(&tent->k.addr6, &ent->a.a6, sizeof(struct in6_addr)); 13860bce0c23SAlexander V. Chernikov tent->masklen = cfg->mask6; 138774b941f0SAlexander V. Chernikov tent->subtype = AF_INET6; 13880cba2b28SAlexander V. Chernikov tent->v.kidx = ent->value; 138974b941f0SAlexander V. Chernikov #endif 139074b941f0SAlexander V. Chernikov } 139174b941f0SAlexander V. Chernikov 139274b941f0SAlexander V. Chernikov return (0); 139374b941f0SAlexander V. Chernikov } 139474b941f0SAlexander V. Chernikov 1395ce2817b5SAlexander V. Chernikov static uint32_t 1396ce2817b5SAlexander V. Chernikov hash_ent(struct chashentry *ent, int af, int mlen, uint32_t size) 1397ce2817b5SAlexander V. Chernikov { 1398ce2817b5SAlexander V. Chernikov uint32_t hash; 1399ce2817b5SAlexander V. Chernikov 1400d699ee2dSAlexander V. Chernikov hash = 0; 1401d699ee2dSAlexander V. Chernikov 1402ce2817b5SAlexander V. Chernikov if (af == AF_INET) { 1403d699ee2dSAlexander V. Chernikov #ifdef INET 1404ce2817b5SAlexander V. Chernikov hash = hash_ip(ent->a.a4, size); 1405d699ee2dSAlexander V. Chernikov #endif 1406ce2817b5SAlexander V. Chernikov } else { 1407d699ee2dSAlexander V. Chernikov #ifdef INET6 1408ce2817b5SAlexander V. Chernikov if (mlen == 64) 1409ce2817b5SAlexander V. Chernikov hash = hash_ip64(&ent->a.a6, size); 1410ce2817b5SAlexander V. Chernikov else 1411ce2817b5SAlexander V. Chernikov hash = hash_ip6(&ent->a.a6, size); 1412d699ee2dSAlexander V. Chernikov #endif 1413ce2817b5SAlexander V. Chernikov } 1414ce2817b5SAlexander V. Chernikov 1415ce2817b5SAlexander V. Chernikov return (hash); 1416ce2817b5SAlexander V. Chernikov } 1417ce2817b5SAlexander V. Chernikov 1418ce2817b5SAlexander V. Chernikov static int 1419ce2817b5SAlexander V. Chernikov tei_to_chash_ent(struct tentry_info *tei, struct chashentry *ent) 1420ce2817b5SAlexander V. Chernikov { 1421ce2817b5SAlexander V. Chernikov int mlen; 1422d699ee2dSAlexander V. Chernikov #ifdef INET6 1423d699ee2dSAlexander V. Chernikov struct in6_addr mask6; 1424d699ee2dSAlexander V. Chernikov #endif 1425ce2817b5SAlexander V. Chernikov 1426ce2817b5SAlexander V. Chernikov 1427ce2817b5SAlexander V. Chernikov mlen = tei->masklen; 1428ce2817b5SAlexander V. Chernikov 1429ce2817b5SAlexander V. Chernikov if (tei->subtype == AF_INET) { 1430ce2817b5SAlexander V. Chernikov #ifdef INET 1431ce2817b5SAlexander V. Chernikov if (mlen > 32) 1432ce2817b5SAlexander V. Chernikov return (EINVAL); 1433ce2817b5SAlexander V. Chernikov ent->type = AF_INET; 1434ce2817b5SAlexander V. Chernikov 1435ce2817b5SAlexander V. Chernikov /* Calculate masked address */ 1436ce2817b5SAlexander V. Chernikov ent->a.a4 = ntohl(*((in_addr_t *)tei->paddr)) >> (32 - mlen); 1437ce2817b5SAlexander V. Chernikov #endif 1438ce2817b5SAlexander V. Chernikov #ifdef INET6 1439ce2817b5SAlexander V. Chernikov } else if (tei->subtype == AF_INET6) { 1440ce2817b5SAlexander V. Chernikov /* IPv6 case */ 1441ce2817b5SAlexander V. Chernikov if (mlen > 128) 1442ce2817b5SAlexander V. Chernikov return (EINVAL); 1443ce2817b5SAlexander V. Chernikov ent->type = AF_INET6; 1444ce2817b5SAlexander V. Chernikov 1445ce2817b5SAlexander V. Chernikov ipv6_writemask(&mask6, mlen); 1446ce2817b5SAlexander V. Chernikov memcpy(&ent->a.a6, tei->paddr, sizeof(struct in6_addr)); 1447ce2817b5SAlexander V. Chernikov APPLY_MASK(&ent->a.a6, &mask6); 1448ce2817b5SAlexander V. Chernikov #endif 1449ce2817b5SAlexander V. Chernikov } else { 1450ce2817b5SAlexander V. Chernikov /* Unknown CIDR type */ 1451ce2817b5SAlexander V. Chernikov return (EINVAL); 1452ce2817b5SAlexander V. Chernikov } 1453ce2817b5SAlexander V. Chernikov 1454ce2817b5SAlexander V. Chernikov return (0); 1455ce2817b5SAlexander V. Chernikov } 1456ce2817b5SAlexander V. Chernikov 145774b941f0SAlexander V. Chernikov static int 1458914bffb6SAlexander V. Chernikov ta_find_chash_tentry(void *ta_state, struct table_info *ti, 1459914bffb6SAlexander V. Chernikov ipfw_obj_tentry *tent) 146074b941f0SAlexander V. Chernikov { 14610bce0c23SAlexander V. Chernikov struct chash_cfg *cfg; 1462ce2817b5SAlexander V. Chernikov struct chashbhead *head; 1463ce2817b5SAlexander V. Chernikov struct chashentry ent, *tmp; 1464ce2817b5SAlexander V. Chernikov struct tentry_info tei; 1465ce2817b5SAlexander V. Chernikov int error; 1466ce2817b5SAlexander V. Chernikov uint32_t hash; 146774b941f0SAlexander V. Chernikov 14680bce0c23SAlexander V. Chernikov cfg = (struct chash_cfg *)ta_state; 1469ce2817b5SAlexander V. Chernikov 1470ce2817b5SAlexander V. Chernikov memset(&ent, 0, sizeof(ent)); 1471ce2817b5SAlexander V. Chernikov memset(&tei, 0, sizeof(tei)); 1472ce2817b5SAlexander V. Chernikov 1473914bffb6SAlexander V. Chernikov if (tent->subtype == AF_INET) { 1474914bffb6SAlexander V. Chernikov tei.paddr = &tent->k.addr; 14750bce0c23SAlexander V. Chernikov tei.masklen = cfg->mask4; 1476ce2817b5SAlexander V. Chernikov tei.subtype = AF_INET; 147774b941f0SAlexander V. Chernikov 1478ce2817b5SAlexander V. Chernikov if ((error = tei_to_chash_ent(&tei, &ent)) != 0) 1479ce2817b5SAlexander V. Chernikov return (error); 1480ce2817b5SAlexander V. Chernikov 14810bce0c23SAlexander V. Chernikov head = cfg->head4; 14820bce0c23SAlexander V. Chernikov hash = hash_ent(&ent, AF_INET, cfg->mask4, cfg->size4); 1483ce2817b5SAlexander V. Chernikov /* Check for existence */ 1484ce2817b5SAlexander V. Chernikov SLIST_FOREACH(tmp, &head[hash], next) { 1485ce2817b5SAlexander V. Chernikov if (tmp->a.a4 != ent.a.a4) 1486ce2817b5SAlexander V. Chernikov continue; 1487ce2817b5SAlexander V. Chernikov 1488ce2817b5SAlexander V. Chernikov ta_dump_chash_tentry(ta_state, ti, tmp, tent); 148974b941f0SAlexander V. Chernikov return (0); 149074b941f0SAlexander V. Chernikov } 1491ce2817b5SAlexander V. Chernikov } else { 1492914bffb6SAlexander V. Chernikov tei.paddr = &tent->k.addr6; 14930bce0c23SAlexander V. Chernikov tei.masklen = cfg->mask6; 1494ce2817b5SAlexander V. Chernikov tei.subtype = AF_INET6; 1495ce2817b5SAlexander V. Chernikov 1496ce2817b5SAlexander V. Chernikov if ((error = tei_to_chash_ent(&tei, &ent)) != 0) 1497ce2817b5SAlexander V. Chernikov return (error); 1498ce2817b5SAlexander V. Chernikov 14990bce0c23SAlexander V. Chernikov head = cfg->head6; 15000bce0c23SAlexander V. Chernikov hash = hash_ent(&ent, AF_INET6, cfg->mask6, cfg->size6); 1501ce2817b5SAlexander V. Chernikov /* Check for existence */ 1502ce2817b5SAlexander V. Chernikov SLIST_FOREACH(tmp, &head[hash], next) { 1503ce2817b5SAlexander V. Chernikov if (memcmp(&tmp->a.a6, &ent.a.a6, 16) != 0) 1504ce2817b5SAlexander V. Chernikov continue; 1505ce2817b5SAlexander V. Chernikov ta_dump_chash_tentry(ta_state, ti, tmp, tent); 1506ce2817b5SAlexander V. Chernikov return (0); 1507ce2817b5SAlexander V. Chernikov } 1508ce2817b5SAlexander V. Chernikov } 1509ce2817b5SAlexander V. Chernikov 151074b941f0SAlexander V. Chernikov return (ENOENT); 151174b941f0SAlexander V. Chernikov } 151274b941f0SAlexander V. Chernikov 151374b941f0SAlexander V. Chernikov static void 151474b941f0SAlexander V. Chernikov ta_foreach_chash(void *ta_state, struct table_info *ti, ta_foreach_f *f, 151574b941f0SAlexander V. Chernikov void *arg) 151674b941f0SAlexander V. Chernikov { 15170bce0c23SAlexander V. Chernikov struct chash_cfg *cfg; 151874b941f0SAlexander V. Chernikov struct chashentry *ent, *ent_next; 151974b941f0SAlexander V. Chernikov int i; 152074b941f0SAlexander V. Chernikov 15210bce0c23SAlexander V. Chernikov cfg = (struct chash_cfg *)ta_state; 152274b941f0SAlexander V. Chernikov 15230bce0c23SAlexander V. Chernikov for (i = 0; i < cfg->size4; i++) 15240bce0c23SAlexander V. Chernikov SLIST_FOREACH_SAFE(ent, &cfg->head4[i], next, ent_next) 152574b941f0SAlexander V. Chernikov f(ent, arg); 152674b941f0SAlexander V. Chernikov 15270bce0c23SAlexander V. Chernikov for (i = 0; i < cfg->size6; i++) 15280bce0c23SAlexander V. Chernikov SLIST_FOREACH_SAFE(ent, &cfg->head6[i], next, ent_next) 152974b941f0SAlexander V. Chernikov f(ent, arg); 153074b941f0SAlexander V. Chernikov } 153174b941f0SAlexander V. Chernikov 153274b941f0SAlexander V. Chernikov static int 153374b941f0SAlexander V. Chernikov ta_prepare_add_chash(struct ip_fw_chain *ch, struct tentry_info *tei, 153474b941f0SAlexander V. Chernikov void *ta_buf) 153574b941f0SAlexander V. Chernikov { 153674b941f0SAlexander V. Chernikov struct ta_buf_chash *tb; 153774b941f0SAlexander V. Chernikov struct chashentry *ent; 1538ce2817b5SAlexander V. Chernikov int error; 153974b941f0SAlexander V. Chernikov 154074b941f0SAlexander V. Chernikov tb = (struct ta_buf_chash *)ta_buf; 154174b941f0SAlexander V. Chernikov 154274b941f0SAlexander V. Chernikov ent = malloc(sizeof(*ent), M_IPFW_TBL, M_WAITOK | M_ZERO); 154374b941f0SAlexander V. Chernikov 1544ce2817b5SAlexander V. Chernikov error = tei_to_chash_ent(tei, ent); 1545ce2817b5SAlexander V. Chernikov if (error != 0) { 1546ce2817b5SAlexander V. Chernikov free(ent, M_IPFW_TBL); 1547ce2817b5SAlexander V. Chernikov return (error); 154874b941f0SAlexander V. Chernikov } 1549ce2817b5SAlexander V. Chernikov tb->ent_ptr = ent; 155074b941f0SAlexander V. Chernikov 155174b941f0SAlexander V. Chernikov return (0); 155274b941f0SAlexander V. Chernikov } 155374b941f0SAlexander V. Chernikov 155474b941f0SAlexander V. Chernikov static int 155574b941f0SAlexander V. Chernikov ta_add_chash(void *ta_state, struct table_info *ti, struct tentry_info *tei, 1556b6ee846eSAlexander V. Chernikov void *ta_buf, uint32_t *pnum) 155774b941f0SAlexander V. Chernikov { 15580bce0c23SAlexander V. Chernikov struct chash_cfg *cfg; 155974b941f0SAlexander V. Chernikov struct chashbhead *head; 156074b941f0SAlexander V. Chernikov struct chashentry *ent, *tmp; 156174b941f0SAlexander V. Chernikov struct ta_buf_chash *tb; 156274b941f0SAlexander V. Chernikov int exists; 1563648e8380SAlexander V. Chernikov uint32_t hash, value; 156474b941f0SAlexander V. Chernikov 15650bce0c23SAlexander V. Chernikov cfg = (struct chash_cfg *)ta_state; 156674b941f0SAlexander V. Chernikov tb = (struct ta_buf_chash *)ta_buf; 156774b941f0SAlexander V. Chernikov ent = (struct chashentry *)tb->ent_ptr; 156874b941f0SAlexander V. Chernikov hash = 0; 156974b941f0SAlexander V. Chernikov exists = 0; 157074b941f0SAlexander V. Chernikov 157113263632SAlexander V. Chernikov /* Read current value from @tei */ 157213263632SAlexander V. Chernikov ent->value = tei->value; 157313263632SAlexander V. Chernikov 157413263632SAlexander V. Chernikov /* Read cuurrent value */ 157574b941f0SAlexander V. Chernikov if (tei->subtype == AF_INET) { 15760bce0c23SAlexander V. Chernikov if (tei->masklen != cfg->mask4) 157774b941f0SAlexander V. Chernikov return (EINVAL); 15780bce0c23SAlexander V. Chernikov head = cfg->head4; 15790bce0c23SAlexander V. Chernikov hash = hash_ent(ent, AF_INET, cfg->mask4, cfg->size4); 1580ce2817b5SAlexander V. Chernikov 158174b941f0SAlexander V. Chernikov /* Check for existence */ 158274b941f0SAlexander V. Chernikov SLIST_FOREACH(tmp, &head[hash], next) { 158374b941f0SAlexander V. Chernikov if (tmp->a.a4 == ent->a.a4) { 158474b941f0SAlexander V. Chernikov exists = 1; 158574b941f0SAlexander V. Chernikov break; 158674b941f0SAlexander V. Chernikov } 158774b941f0SAlexander V. Chernikov } 158874b941f0SAlexander V. Chernikov } else { 15890bce0c23SAlexander V. Chernikov if (tei->masklen != cfg->mask6) 159074b941f0SAlexander V. Chernikov return (EINVAL); 15910bce0c23SAlexander V. Chernikov head = cfg->head6; 15920bce0c23SAlexander V. Chernikov hash = hash_ent(ent, AF_INET6, cfg->mask6, cfg->size6); 159374b941f0SAlexander V. Chernikov /* Check for existence */ 159474b941f0SAlexander V. Chernikov SLIST_FOREACH(tmp, &head[hash], next) { 1595ce2817b5SAlexander V. Chernikov if (memcmp(&tmp->a.a6, &ent->a.a6, 16) == 0) { 159674b941f0SAlexander V. Chernikov exists = 1; 159774b941f0SAlexander V. Chernikov break; 159874b941f0SAlexander V. Chernikov } 159974b941f0SAlexander V. Chernikov } 160074b941f0SAlexander V. Chernikov } 160174b941f0SAlexander V. Chernikov 160274b941f0SAlexander V. Chernikov if (exists == 1) { 160374b941f0SAlexander V. Chernikov if ((tei->flags & TEI_FLAGS_UPDATE) == 0) 160474b941f0SAlexander V. Chernikov return (EEXIST); 160574b941f0SAlexander V. Chernikov /* Record already exists. Update value if we're asked to */ 1606648e8380SAlexander V. Chernikov value = tmp->value; 160774b941f0SAlexander V. Chernikov tmp->value = tei->value; 1608648e8380SAlexander V. Chernikov tei->value = value; 160974b941f0SAlexander V. Chernikov /* Indicate that update has happened instead of addition */ 161074b941f0SAlexander V. Chernikov tei->flags |= TEI_FLAGS_UPDATED; 161174b941f0SAlexander V. Chernikov *pnum = 0; 161274b941f0SAlexander V. Chernikov } else { 16134c0c07a5SAlexander V. Chernikov if ((tei->flags & TEI_FLAGS_DONTADD) != 0) 16144c0c07a5SAlexander V. Chernikov return (EFBIG); 161574b941f0SAlexander V. Chernikov SLIST_INSERT_HEAD(&head[hash], ent, next); 161674b941f0SAlexander V. Chernikov tb->ent_ptr = NULL; 161774b941f0SAlexander V. Chernikov *pnum = 1; 1618ce2817b5SAlexander V. Chernikov 1619b6ee846eSAlexander V. Chernikov /* Update counters */ 1620b6ee846eSAlexander V. Chernikov if (tei->subtype == AF_INET) 16210bce0c23SAlexander V. Chernikov cfg->items4++; 1622b6ee846eSAlexander V. Chernikov else 16230bce0c23SAlexander V. Chernikov cfg->items6++; 162474b941f0SAlexander V. Chernikov } 162574b941f0SAlexander V. Chernikov 162674b941f0SAlexander V. Chernikov return (0); 162774b941f0SAlexander V. Chernikov } 162874b941f0SAlexander V. Chernikov 162974b941f0SAlexander V. Chernikov static int 163074b941f0SAlexander V. Chernikov ta_prepare_del_chash(struct ip_fw_chain *ch, struct tentry_info *tei, 163174b941f0SAlexander V. Chernikov void *ta_buf) 163274b941f0SAlexander V. Chernikov { 163374b941f0SAlexander V. Chernikov struct ta_buf_chash *tb; 163474b941f0SAlexander V. Chernikov 163574b941f0SAlexander V. Chernikov tb = (struct ta_buf_chash *)ta_buf; 163674b941f0SAlexander V. Chernikov 1637ce2817b5SAlexander V. Chernikov return (tei_to_chash_ent(tei, &tb->ent)); 163874b941f0SAlexander V. Chernikov } 163974b941f0SAlexander V. Chernikov 164074b941f0SAlexander V. Chernikov static int 164174b941f0SAlexander V. Chernikov ta_del_chash(void *ta_state, struct table_info *ti, struct tentry_info *tei, 1642b6ee846eSAlexander V. Chernikov void *ta_buf, uint32_t *pnum) 164374b941f0SAlexander V. Chernikov { 16440bce0c23SAlexander V. Chernikov struct chash_cfg *cfg; 164574b941f0SAlexander V. Chernikov struct chashbhead *head; 16460bce0c23SAlexander V. Chernikov struct chashentry *tmp, *tmp_next, *ent; 164774b941f0SAlexander V. Chernikov struct ta_buf_chash *tb; 164874b941f0SAlexander V. Chernikov uint32_t hash; 164974b941f0SAlexander V. Chernikov 16500bce0c23SAlexander V. Chernikov cfg = (struct chash_cfg *)ta_state; 165174b941f0SAlexander V. Chernikov tb = (struct ta_buf_chash *)ta_buf; 16520bce0c23SAlexander V. Chernikov ent = &tb->ent; 165374b941f0SAlexander V. Chernikov 165474b941f0SAlexander V. Chernikov if (tei->subtype == AF_INET) { 16550bce0c23SAlexander V. Chernikov if (tei->masklen != cfg->mask4) 165674b941f0SAlexander V. Chernikov return (EINVAL); 16570bce0c23SAlexander V. Chernikov head = cfg->head4; 16580bce0c23SAlexander V. Chernikov hash = hash_ent(ent, AF_INET, cfg->mask4, cfg->size4); 165974b941f0SAlexander V. Chernikov 16600bce0c23SAlexander V. Chernikov SLIST_FOREACH_SAFE(tmp, &head[hash], next, tmp_next) { 16610bce0c23SAlexander V. Chernikov if (tmp->a.a4 != ent->a.a4) 1662648e8380SAlexander V. Chernikov continue; 1663648e8380SAlexander V. Chernikov 16640bce0c23SAlexander V. Chernikov SLIST_REMOVE(&head[hash], tmp, chashentry, next); 16650bce0c23SAlexander V. Chernikov cfg->items4--; 16660bce0c23SAlexander V. Chernikov tb->ent_ptr = tmp; 16670bce0c23SAlexander V. Chernikov tei->value = tmp->value; 1668648e8380SAlexander V. Chernikov *pnum = 1; 166974b941f0SAlexander V. Chernikov return (0); 167074b941f0SAlexander V. Chernikov } 167174b941f0SAlexander V. Chernikov } else { 16720bce0c23SAlexander V. Chernikov if (tei->masklen != cfg->mask6) 167374b941f0SAlexander V. Chernikov return (EINVAL); 16740bce0c23SAlexander V. Chernikov head = cfg->head6; 16750bce0c23SAlexander V. Chernikov hash = hash_ent(ent, AF_INET6, cfg->mask6, cfg->size6); 16760bce0c23SAlexander V. Chernikov SLIST_FOREACH_SAFE(tmp, &head[hash], next, tmp_next) { 16770bce0c23SAlexander V. Chernikov if (memcmp(&tmp->a.a6, &ent->a.a6, 16) != 0) 1678648e8380SAlexander V. Chernikov continue; 1679648e8380SAlexander V. Chernikov 16800bce0c23SAlexander V. Chernikov SLIST_REMOVE(&head[hash], tmp, chashentry, next); 16810bce0c23SAlexander V. Chernikov cfg->items6--; 16820bce0c23SAlexander V. Chernikov tb->ent_ptr = tmp; 16830bce0c23SAlexander V. Chernikov tei->value = tmp->value; 168474b941f0SAlexander V. Chernikov *pnum = 1; 168574b941f0SAlexander V. Chernikov return (0); 168674b941f0SAlexander V. Chernikov } 168774b941f0SAlexander V. Chernikov } 168874b941f0SAlexander V. Chernikov 168974b941f0SAlexander V. Chernikov return (ENOENT); 169074b941f0SAlexander V. Chernikov } 169174b941f0SAlexander V. Chernikov 169274b941f0SAlexander V. Chernikov static void 169374b941f0SAlexander V. Chernikov ta_flush_chash_entry(struct ip_fw_chain *ch, struct tentry_info *tei, 169474b941f0SAlexander V. Chernikov void *ta_buf) 169574b941f0SAlexander V. Chernikov { 169674b941f0SAlexander V. Chernikov struct ta_buf_chash *tb; 169774b941f0SAlexander V. Chernikov 169874b941f0SAlexander V. Chernikov tb = (struct ta_buf_chash *)ta_buf; 169974b941f0SAlexander V. Chernikov 170074b941f0SAlexander V. Chernikov if (tb->ent_ptr != NULL) 170174b941f0SAlexander V. Chernikov free(tb->ent_ptr, M_IPFW_TBL); 170274b941f0SAlexander V. Chernikov } 170374b941f0SAlexander V. Chernikov 1704ce2817b5SAlexander V. Chernikov /* 1705ce2817b5SAlexander V. Chernikov * Hash growing callbacks. 1706ce2817b5SAlexander V. Chernikov */ 1707ce2817b5SAlexander V. Chernikov 1708b6ee846eSAlexander V. Chernikov static int 1709301290bcSAlexander V. Chernikov ta_need_modify_chash(void *ta_state, struct table_info *ti, uint32_t count, 1710b6ee846eSAlexander V. Chernikov uint64_t *pflags) 1711b6ee846eSAlexander V. Chernikov { 1712b6ee846eSAlexander V. Chernikov struct chash_cfg *cfg; 1713b6ee846eSAlexander V. Chernikov uint64_t data; 1714b6ee846eSAlexander V. Chernikov 1715b6ee846eSAlexander V. Chernikov /* 1716b6ee846eSAlexander V. Chernikov * Since we don't know exact number of IPv4/IPv6 records in @count, 1717b6ee846eSAlexander V. Chernikov * ignore non-zero @count value at all. Check current hash sizes 1718b6ee846eSAlexander V. Chernikov * and return appropriate data. 1719b6ee846eSAlexander V. Chernikov */ 1720b6ee846eSAlexander V. Chernikov 1721b6ee846eSAlexander V. Chernikov cfg = (struct chash_cfg *)ta_state; 1722b6ee846eSAlexander V. Chernikov 1723b6ee846eSAlexander V. Chernikov data = 0; 1724b6ee846eSAlexander V. Chernikov if (cfg->items4 > cfg->size4 && cfg->size4 < 65536) 1725b6ee846eSAlexander V. Chernikov data |= (cfg->size4 * 2) << 16; 1726b6ee846eSAlexander V. Chernikov if (cfg->items6 > cfg->size6 && cfg->size6 < 65536) 1727b6ee846eSAlexander V. Chernikov data |= cfg->size6 * 2; 1728b6ee846eSAlexander V. Chernikov 1729b6ee846eSAlexander V. Chernikov if (data != 0) { 1730b6ee846eSAlexander V. Chernikov *pflags = data; 1731301290bcSAlexander V. Chernikov return (1); 1732b6ee846eSAlexander V. Chernikov } 1733b6ee846eSAlexander V. Chernikov 1734301290bcSAlexander V. Chernikov return (0); 1735b6ee846eSAlexander V. Chernikov } 1736b6ee846eSAlexander V. Chernikov 1737ce2817b5SAlexander V. Chernikov /* 1738ce2817b5SAlexander V. Chernikov * Allocate new, larger chash. 1739ce2817b5SAlexander V. Chernikov */ 1740ce2817b5SAlexander V. Chernikov static int 1741ce2817b5SAlexander V. Chernikov ta_prepare_mod_chash(void *ta_buf, uint64_t *pflags) 1742ce2817b5SAlexander V. Chernikov { 1743ce2817b5SAlexander V. Chernikov struct mod_item *mi; 1744ce2817b5SAlexander V. Chernikov struct chashbhead *head; 1745ce2817b5SAlexander V. Chernikov int i; 1746ce2817b5SAlexander V. Chernikov 1747ce2817b5SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 1748ce2817b5SAlexander V. Chernikov 1749ce2817b5SAlexander V. Chernikov memset(mi, 0, sizeof(struct mod_item)); 1750b6ee846eSAlexander V. Chernikov mi->size = (*pflags >> 16) & 0xFFFF; 1751b6ee846eSAlexander V. Chernikov mi->size6 = *pflags & 0xFFFF; 1752b6ee846eSAlexander V. Chernikov if (mi->size > 0) { 1753b6ee846eSAlexander V. Chernikov head = malloc(sizeof(struct chashbhead) * mi->size, 1754b6ee846eSAlexander V. Chernikov M_IPFW, M_WAITOK | M_ZERO); 1755ce2817b5SAlexander V. Chernikov for (i = 0; i < mi->size; i++) 1756ce2817b5SAlexander V. Chernikov SLIST_INIT(&head[i]); 1757ce2817b5SAlexander V. Chernikov mi->main_ptr = head; 1758b6ee846eSAlexander V. Chernikov } 1759b6ee846eSAlexander V. Chernikov 1760b6ee846eSAlexander V. Chernikov if (mi->size6 > 0) { 1761b6ee846eSAlexander V. Chernikov head = malloc(sizeof(struct chashbhead) * mi->size6, 1762b6ee846eSAlexander V. Chernikov M_IPFW, M_WAITOK | M_ZERO); 1763b6ee846eSAlexander V. Chernikov for (i = 0; i < mi->size6; i++) 1764b6ee846eSAlexander V. Chernikov SLIST_INIT(&head[i]); 1765b6ee846eSAlexander V. Chernikov mi->main_ptr6 = head; 1766b6ee846eSAlexander V. Chernikov } 1767ce2817b5SAlexander V. Chernikov 1768ce2817b5SAlexander V. Chernikov return (0); 1769ce2817b5SAlexander V. Chernikov } 1770ce2817b5SAlexander V. Chernikov 1771ce2817b5SAlexander V. Chernikov /* 1772ce2817b5SAlexander V. Chernikov * Copy data from old runtime array to new one. 1773ce2817b5SAlexander V. Chernikov */ 1774ce2817b5SAlexander V. Chernikov static int 1775ce2817b5SAlexander V. Chernikov ta_fill_mod_chash(void *ta_state, struct table_info *ti, void *ta_buf, 1776ce2817b5SAlexander V. Chernikov uint64_t *pflags) 1777ce2817b5SAlexander V. Chernikov { 1778ce2817b5SAlexander V. Chernikov 1779ce2817b5SAlexander V. Chernikov /* In is not possible to do rehash if we're not holidng WLOCK. */ 1780ce2817b5SAlexander V. Chernikov return (0); 1781ce2817b5SAlexander V. Chernikov } 1782ce2817b5SAlexander V. Chernikov 1783ce2817b5SAlexander V. Chernikov /* 1784ce2817b5SAlexander V. Chernikov * Switch old & new arrays. 1785ce2817b5SAlexander V. Chernikov */ 1786301290bcSAlexander V. Chernikov static void 1787ce2817b5SAlexander V. Chernikov ta_modify_chash(void *ta_state, struct table_info *ti, void *ta_buf, 1788ce2817b5SAlexander V. Chernikov uint64_t pflags) 1789ce2817b5SAlexander V. Chernikov { 1790ce2817b5SAlexander V. Chernikov struct mod_item *mi; 1791b6ee846eSAlexander V. Chernikov struct chash_cfg *cfg; 1792ce2817b5SAlexander V. Chernikov struct chashbhead *old_head, *new_head; 1793ce2817b5SAlexander V. Chernikov struct chashentry *ent, *ent_next; 1794ce2817b5SAlexander V. Chernikov int af, i, mlen; 1795ce2817b5SAlexander V. Chernikov uint32_t nhash; 1796b6ee846eSAlexander V. Chernikov size_t old_size, new_size; 1797ce2817b5SAlexander V. Chernikov 1798ce2817b5SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 1799b6ee846eSAlexander V. Chernikov cfg = (struct chash_cfg *)ta_state; 1800ce2817b5SAlexander V. Chernikov 1801ce2817b5SAlexander V. Chernikov /* Check which hash we need to grow and do we still need that */ 1802b6ee846eSAlexander V. Chernikov if (mi->size > 0 && cfg->size4 < mi->size) { 1803ce2817b5SAlexander V. Chernikov new_head = (struct chashbhead *)mi->main_ptr; 1804b6ee846eSAlexander V. Chernikov new_size = mi->size; 1805b6ee846eSAlexander V. Chernikov old_size = cfg->size4; 1806b6ee846eSAlexander V. Chernikov old_head = ti->state; 1807b6ee846eSAlexander V. Chernikov mlen = cfg->mask4; 1808b6ee846eSAlexander V. Chernikov af = AF_INET; 1809b6ee846eSAlexander V. Chernikov 1810ce2817b5SAlexander V. Chernikov for (i = 0; i < old_size; i++) { 1811ce2817b5SAlexander V. Chernikov SLIST_FOREACH_SAFE(ent, &old_head[i], next, ent_next) { 1812b6ee846eSAlexander V. Chernikov nhash = hash_ent(ent, af, mlen, new_size); 1813ce2817b5SAlexander V. Chernikov SLIST_INSERT_HEAD(&new_head[nhash], ent, next); 1814ce2817b5SAlexander V. Chernikov } 1815ce2817b5SAlexander V. Chernikov } 1816ce2817b5SAlexander V. Chernikov 1817ce2817b5SAlexander V. Chernikov ti->state = new_head; 1818b6ee846eSAlexander V. Chernikov cfg->head4 = new_head; 1819b6ee846eSAlexander V. Chernikov cfg->size4 = mi->size; 1820b6ee846eSAlexander V. Chernikov mi->main_ptr = old_head; 1821ce2817b5SAlexander V. Chernikov } 1822ce2817b5SAlexander V. Chernikov 1823b6ee846eSAlexander V. Chernikov if (mi->size6 > 0 && cfg->size6 < mi->size6) { 1824b6ee846eSAlexander V. Chernikov new_head = (struct chashbhead *)mi->main_ptr6; 1825b6ee846eSAlexander V. Chernikov new_size = mi->size6; 1826b6ee846eSAlexander V. Chernikov old_size = cfg->size6; 1827b6ee846eSAlexander V. Chernikov old_head = ti->xstate; 1828b6ee846eSAlexander V. Chernikov mlen = cfg->mask6; 1829b6ee846eSAlexander V. Chernikov af = AF_INET6; 1830914bffb6SAlexander V. Chernikov 1831b6ee846eSAlexander V. Chernikov for (i = 0; i < old_size; i++) { 1832b6ee846eSAlexander V. Chernikov SLIST_FOREACH_SAFE(ent, &old_head[i], next, ent_next) { 1833b6ee846eSAlexander V. Chernikov nhash = hash_ent(ent, af, mlen, new_size); 1834b6ee846eSAlexander V. Chernikov SLIST_INSERT_HEAD(&new_head[nhash], ent, next); 1835b6ee846eSAlexander V. Chernikov } 1836b6ee846eSAlexander V. Chernikov } 1837b6ee846eSAlexander V. Chernikov 1838b6ee846eSAlexander V. Chernikov ti->xstate = new_head; 1839b6ee846eSAlexander V. Chernikov cfg->head6 = new_head; 1840b6ee846eSAlexander V. Chernikov cfg->size6 = mi->size6; 1841b6ee846eSAlexander V. Chernikov mi->main_ptr6 = old_head; 1842b6ee846eSAlexander V. Chernikov } 1843b6ee846eSAlexander V. Chernikov 1844b6ee846eSAlexander V. Chernikov /* Update lower 32 bits with new values */ 1845b6ee846eSAlexander V. Chernikov ti->data &= 0xFFFFFFFF00000000; 18469e3a53fdSAlexander V. Chernikov ti->data |= ta_log2(cfg->size4) << 8 | ta_log2(cfg->size6); 1847ce2817b5SAlexander V. Chernikov } 1848ce2817b5SAlexander V. Chernikov 1849ce2817b5SAlexander V. Chernikov /* 1850ce2817b5SAlexander V. Chernikov * Free unneded array. 1851ce2817b5SAlexander V. Chernikov */ 1852ce2817b5SAlexander V. Chernikov static void 1853ce2817b5SAlexander V. Chernikov ta_flush_mod_chash(void *ta_buf) 1854ce2817b5SAlexander V. Chernikov { 1855ce2817b5SAlexander V. Chernikov struct mod_item *mi; 1856ce2817b5SAlexander V. Chernikov 1857ce2817b5SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 1858ce2817b5SAlexander V. Chernikov if (mi->main_ptr != NULL) 1859ce2817b5SAlexander V. Chernikov free(mi->main_ptr, M_IPFW); 1860b6ee846eSAlexander V. Chernikov if (mi->main_ptr6 != NULL) 1861b6ee846eSAlexander V. Chernikov free(mi->main_ptr6, M_IPFW); 1862ce2817b5SAlexander V. Chernikov } 1863ce2817b5SAlexander V. Chernikov 1864c21034b7SAlexander V. Chernikov struct table_algo addr_hash = { 1865c21034b7SAlexander V. Chernikov .name = "addr:hash", 1866c21034b7SAlexander V. Chernikov .type = IPFW_TABLE_ADDR, 186757a1cf95SAlexander V. Chernikov .ta_buf_size = sizeof(struct ta_buf_chash), 186874b941f0SAlexander V. Chernikov .init = ta_init_chash, 186974b941f0SAlexander V. Chernikov .destroy = ta_destroy_chash, 187074b941f0SAlexander V. Chernikov .prepare_add = ta_prepare_add_chash, 187174b941f0SAlexander V. Chernikov .prepare_del = ta_prepare_del_chash, 187274b941f0SAlexander V. Chernikov .add = ta_add_chash, 187374b941f0SAlexander V. Chernikov .del = ta_del_chash, 187474b941f0SAlexander V. Chernikov .flush_entry = ta_flush_chash_entry, 187574b941f0SAlexander V. Chernikov .foreach = ta_foreach_chash, 187674b941f0SAlexander V. Chernikov .dump_tentry = ta_dump_chash_tentry, 187774b941f0SAlexander V. Chernikov .find_tentry = ta_find_chash_tentry, 187874b941f0SAlexander V. Chernikov .print_config = ta_print_chash_config, 18795f379342SAlexander V. Chernikov .dump_tinfo = ta_dump_chash_tinfo, 1880301290bcSAlexander V. Chernikov .need_modify = ta_need_modify_chash, 1881ce2817b5SAlexander V. Chernikov .prepare_mod = ta_prepare_mod_chash, 1882ce2817b5SAlexander V. Chernikov .fill_mod = ta_fill_mod_chash, 1883ce2817b5SAlexander V. Chernikov .modify = ta_modify_chash, 1884ce2817b5SAlexander V. Chernikov .flush_mod = ta_flush_mod_chash, 188574b941f0SAlexander V. Chernikov }; 188674b941f0SAlexander V. Chernikov 188774b941f0SAlexander V. Chernikov 188874b941f0SAlexander V. Chernikov /* 188968394ec8SAlexander V. Chernikov * Iface table cmds. 189068394ec8SAlexander V. Chernikov * 189168394ec8SAlexander V. Chernikov * Implementation: 189268394ec8SAlexander V. Chernikov * 189368394ec8SAlexander V. Chernikov * Runtime part: 189468394ec8SAlexander V. Chernikov * - sorted array of "struct ifidx" pointed by ti->state. 1895b23d5de9SAlexander V. Chernikov * Array is allocated with rounding up to IFIDX_CHUNK. Only existing 189668394ec8SAlexander V. Chernikov * interfaces are stored in array, however its allocated size is 189768394ec8SAlexander V. Chernikov * sufficient to hold all table records if needed. 189868394ec8SAlexander V. Chernikov * - current array size is stored in ti->data 189968394ec8SAlexander V. Chernikov * 190068394ec8SAlexander V. Chernikov * Table data: 190168394ec8SAlexander V. Chernikov * - "struct iftable_cfg" is allocated to store table state (ta_state). 190268394ec8SAlexander V. Chernikov * - All table records are stored inside namedobj instance. 19039f7d47b0SAlexander V. Chernikov * 19049f7d47b0SAlexander V. Chernikov */ 19059f7d47b0SAlexander V. Chernikov 190668394ec8SAlexander V. Chernikov struct ifidx { 190768394ec8SAlexander V. Chernikov uint16_t kidx; 190868394ec8SAlexander V. Chernikov uint16_t spare; 190968394ec8SAlexander V. Chernikov uint32_t value; 191068394ec8SAlexander V. Chernikov }; 19110cba2b28SAlexander V. Chernikov #define DEFAULT_IFIDX_SIZE 64 191268394ec8SAlexander V. Chernikov 191368394ec8SAlexander V. Chernikov struct iftable_cfg; 191468394ec8SAlexander V. Chernikov 191568394ec8SAlexander V. Chernikov struct ifentry { 191668394ec8SAlexander V. Chernikov struct named_object no; 191768394ec8SAlexander V. Chernikov struct ipfw_ifc ic; 191868394ec8SAlexander V. Chernikov struct iftable_cfg *icfg; 191968394ec8SAlexander V. Chernikov uint32_t value; 192068394ec8SAlexander V. Chernikov int linked; 192168394ec8SAlexander V. Chernikov }; 192268394ec8SAlexander V. Chernikov 192368394ec8SAlexander V. Chernikov struct iftable_cfg { 192468394ec8SAlexander V. Chernikov struct namedobj_instance *ii; 192568394ec8SAlexander V. Chernikov struct ip_fw_chain *ch; 192668394ec8SAlexander V. Chernikov struct table_info *ti; 192768394ec8SAlexander V. Chernikov void *main_ptr; 192868394ec8SAlexander V. Chernikov size_t size; /* Number of items allocated in array */ 192968394ec8SAlexander V. Chernikov size_t count; /* Number of all items */ 193068394ec8SAlexander V. Chernikov size_t used; /* Number of items _active_ now */ 193168394ec8SAlexander V. Chernikov }; 193268394ec8SAlexander V. Chernikov 19330bce0c23SAlexander V. Chernikov struct ta_buf_ifidx 19340bce0c23SAlexander V. Chernikov { 19350bce0c23SAlexander V. Chernikov struct ifentry *ife; 19360bce0c23SAlexander V. Chernikov uint32_t value; 19370bce0c23SAlexander V. Chernikov }; 193868394ec8SAlexander V. Chernikov 193968394ec8SAlexander V. Chernikov int compare_ifidx(const void *k, const void *v); 19409fe15d06SAlexander V. Chernikov static struct ifidx * ifidx_find(struct table_info *ti, void *key); 19419fe15d06SAlexander V. Chernikov static int ta_lookup_ifidx(struct table_info *ti, void *key, uint32_t keylen, 19429fe15d06SAlexander V. Chernikov uint32_t *val); 19439fe15d06SAlexander V. Chernikov static int ta_init_ifidx(struct ip_fw_chain *ch, void **ta_state, 19449fe15d06SAlexander V. Chernikov struct table_info *ti, char *data, uint8_t tflags); 19459fe15d06SAlexander V. Chernikov static void ta_change_ti_ifidx(void *ta_state, struct table_info *ti); 1946b309f085SAndrey V. Elsukov static int destroy_ifidx_locked(struct namedobj_instance *ii, 19479fe15d06SAlexander V. Chernikov struct named_object *no, void *arg); 19489fe15d06SAlexander V. Chernikov static void ta_destroy_ifidx(void *ta_state, struct table_info *ti); 19499fe15d06SAlexander V. Chernikov static void ta_dump_ifidx_tinfo(void *ta_state, struct table_info *ti, 19509fe15d06SAlexander V. Chernikov ipfw_ta_tinfo *tinfo); 19519fe15d06SAlexander V. Chernikov static int ta_prepare_add_ifidx(struct ip_fw_chain *ch, struct tentry_info *tei, 19529fe15d06SAlexander V. Chernikov void *ta_buf); 19539fe15d06SAlexander V. Chernikov static int ta_add_ifidx(void *ta_state, struct table_info *ti, 19549fe15d06SAlexander V. Chernikov struct tentry_info *tei, void *ta_buf, uint32_t *pnum); 19559fe15d06SAlexander V. Chernikov static int ta_prepare_del_ifidx(struct ip_fw_chain *ch, struct tentry_info *tei, 19569fe15d06SAlexander V. Chernikov void *ta_buf); 19579fe15d06SAlexander V. Chernikov static int ta_del_ifidx(void *ta_state, struct table_info *ti, 19589fe15d06SAlexander V. Chernikov struct tentry_info *tei, void *ta_buf, uint32_t *pnum); 19599fe15d06SAlexander V. Chernikov static void ta_flush_ifidx_entry(struct ip_fw_chain *ch, 19609fe15d06SAlexander V. Chernikov struct tentry_info *tei, void *ta_buf); 19619fe15d06SAlexander V. Chernikov static void if_notifier(struct ip_fw_chain *ch, void *cbdata, uint16_t ifindex); 19629fe15d06SAlexander V. Chernikov static int ta_need_modify_ifidx(void *ta_state, struct table_info *ti, 19639fe15d06SAlexander V. Chernikov uint32_t count, uint64_t *pflags); 19649fe15d06SAlexander V. Chernikov static int ta_prepare_mod_ifidx(void *ta_buf, uint64_t *pflags); 19659fe15d06SAlexander V. Chernikov static int ta_fill_mod_ifidx(void *ta_state, struct table_info *ti, 19669fe15d06SAlexander V. Chernikov void *ta_buf, uint64_t *pflags); 19679fe15d06SAlexander V. Chernikov static void ta_modify_ifidx(void *ta_state, struct table_info *ti, void *ta_buf, 19689fe15d06SAlexander V. Chernikov uint64_t pflags); 19699fe15d06SAlexander V. Chernikov static void ta_flush_mod_ifidx(void *ta_buf); 19709fe15d06SAlexander V. Chernikov static int ta_dump_ifidx_tentry(void *ta_state, struct table_info *ti, void *e, 19719fe15d06SAlexander V. Chernikov ipfw_obj_tentry *tent); 19729fe15d06SAlexander V. Chernikov static int ta_find_ifidx_tentry(void *ta_state, struct table_info *ti, 19739fe15d06SAlexander V. Chernikov ipfw_obj_tentry *tent); 1974b309f085SAndrey V. Elsukov static int foreach_ifidx(struct namedobj_instance *ii, struct named_object *no, 19759fe15d06SAlexander V. Chernikov void *arg); 19769fe15d06SAlexander V. Chernikov static void ta_foreach_ifidx(void *ta_state, struct table_info *ti, 19779fe15d06SAlexander V. Chernikov ta_foreach_f *f, void *arg); 197868394ec8SAlexander V. Chernikov 197968394ec8SAlexander V. Chernikov int 198068394ec8SAlexander V. Chernikov compare_ifidx(const void *k, const void *v) 198168394ec8SAlexander V. Chernikov { 1982d4e1b515SAlexander V. Chernikov const struct ifidx *ifidx; 198368394ec8SAlexander V. Chernikov uint16_t key; 198468394ec8SAlexander V. Chernikov 1985d4e1b515SAlexander V. Chernikov key = *((const uint16_t *)k); 1986d4e1b515SAlexander V. Chernikov ifidx = (const struct ifidx *)v; 198768394ec8SAlexander V. Chernikov 198868394ec8SAlexander V. Chernikov if (key < ifidx->kidx) 198968394ec8SAlexander V. Chernikov return (-1); 199068394ec8SAlexander V. Chernikov else if (key > ifidx->kidx) 199168394ec8SAlexander V. Chernikov return (1); 199268394ec8SAlexander V. Chernikov 199368394ec8SAlexander V. Chernikov return (0); 199468394ec8SAlexander V. Chernikov } 199568394ec8SAlexander V. Chernikov 199668394ec8SAlexander V. Chernikov /* 199768394ec8SAlexander V. Chernikov * Adds item @item with key @key into ascending-sorted array @base. 199868394ec8SAlexander V. Chernikov * Assumes @base has enough additional storage. 199968394ec8SAlexander V. Chernikov * 200068394ec8SAlexander V. Chernikov * Returns 1 on success, 0 on duplicate key. 200168394ec8SAlexander V. Chernikov */ 20029f7d47b0SAlexander V. Chernikov static int 200368394ec8SAlexander V. Chernikov badd(const void *key, void *item, void *base, size_t nmemb, 200468394ec8SAlexander V. Chernikov size_t size, int (*compar) (const void *, const void *)) 200568394ec8SAlexander V. Chernikov { 200668394ec8SAlexander V. Chernikov int min, max, mid, shift, res; 200768394ec8SAlexander V. Chernikov caddr_t paddr; 200868394ec8SAlexander V. Chernikov 200968394ec8SAlexander V. Chernikov if (nmemb == 0) { 201068394ec8SAlexander V. Chernikov memcpy(base, item, size); 201168394ec8SAlexander V. Chernikov return (1); 201268394ec8SAlexander V. Chernikov } 201368394ec8SAlexander V. Chernikov 201468394ec8SAlexander V. Chernikov /* Binary search */ 201568394ec8SAlexander V. Chernikov min = 0; 201668394ec8SAlexander V. Chernikov max = nmemb - 1; 201768394ec8SAlexander V. Chernikov mid = 0; 201868394ec8SAlexander V. Chernikov while (min <= max) { 201968394ec8SAlexander V. Chernikov mid = (min + max) / 2; 202068394ec8SAlexander V. Chernikov res = compar(key, (const void *)((caddr_t)base + mid * size)); 202168394ec8SAlexander V. Chernikov if (res == 0) 202268394ec8SAlexander V. Chernikov return (0); 202368394ec8SAlexander V. Chernikov 202468394ec8SAlexander V. Chernikov if (res > 0) 202568394ec8SAlexander V. Chernikov min = mid + 1; 202668394ec8SAlexander V. Chernikov else 202768394ec8SAlexander V. Chernikov max = mid - 1; 202868394ec8SAlexander V. Chernikov } 202968394ec8SAlexander V. Chernikov 203068394ec8SAlexander V. Chernikov /* Item not found. */ 203168394ec8SAlexander V. Chernikov res = compar(key, (const void *)((caddr_t)base + mid * size)); 203268394ec8SAlexander V. Chernikov if (res > 0) 203368394ec8SAlexander V. Chernikov shift = mid + 1; 203468394ec8SAlexander V. Chernikov else 203568394ec8SAlexander V. Chernikov shift = mid; 203668394ec8SAlexander V. Chernikov 203768394ec8SAlexander V. Chernikov paddr = (caddr_t)base + shift * size; 203868394ec8SAlexander V. Chernikov if (nmemb > shift) 203968394ec8SAlexander V. Chernikov memmove(paddr + size, paddr, (nmemb - shift) * size); 204068394ec8SAlexander V. Chernikov 204168394ec8SAlexander V. Chernikov memcpy(paddr, item, size); 204268394ec8SAlexander V. Chernikov 204368394ec8SAlexander V. Chernikov return (1); 204468394ec8SAlexander V. Chernikov } 204568394ec8SAlexander V. Chernikov 204668394ec8SAlexander V. Chernikov /* 204768394ec8SAlexander V. Chernikov * Deletes item with key @key from ascending-sorted array @base. 204868394ec8SAlexander V. Chernikov * 204968394ec8SAlexander V. Chernikov * Returns 1 on success, 0 for non-existent key. 205068394ec8SAlexander V. Chernikov */ 205168394ec8SAlexander V. Chernikov static int 205268394ec8SAlexander V. Chernikov bdel(const void *key, void *base, size_t nmemb, size_t size, 205368394ec8SAlexander V. Chernikov int (*compar) (const void *, const void *)) 205468394ec8SAlexander V. Chernikov { 205568394ec8SAlexander V. Chernikov caddr_t item; 205668394ec8SAlexander V. Chernikov size_t sz; 205768394ec8SAlexander V. Chernikov 205868394ec8SAlexander V. Chernikov item = (caddr_t)bsearch(key, base, nmemb, size, compar); 205968394ec8SAlexander V. Chernikov 206068394ec8SAlexander V. Chernikov if (item == NULL) 206168394ec8SAlexander V. Chernikov return (0); 206268394ec8SAlexander V. Chernikov 206368394ec8SAlexander V. Chernikov sz = (caddr_t)base + nmemb * size - item; 206468394ec8SAlexander V. Chernikov 206568394ec8SAlexander V. Chernikov if (sz > 0) 206668394ec8SAlexander V. Chernikov memmove(item, item + size, sz); 206768394ec8SAlexander V. Chernikov 206868394ec8SAlexander V. Chernikov return (1); 206968394ec8SAlexander V. Chernikov } 207068394ec8SAlexander V. Chernikov 207168394ec8SAlexander V. Chernikov static struct ifidx * 207268394ec8SAlexander V. Chernikov ifidx_find(struct table_info *ti, void *key) 207368394ec8SAlexander V. Chernikov { 207468394ec8SAlexander V. Chernikov struct ifidx *ifi; 207568394ec8SAlexander V. Chernikov 207668394ec8SAlexander V. Chernikov ifi = bsearch(key, ti->state, ti->data, sizeof(struct ifidx), 207768394ec8SAlexander V. Chernikov compare_ifidx); 207868394ec8SAlexander V. Chernikov 207968394ec8SAlexander V. Chernikov return (ifi); 208068394ec8SAlexander V. Chernikov } 208168394ec8SAlexander V. Chernikov 208268394ec8SAlexander V. Chernikov static int 208368394ec8SAlexander V. Chernikov ta_lookup_ifidx(struct table_info *ti, void *key, uint32_t keylen, 20849f7d47b0SAlexander V. Chernikov uint32_t *val) 20859f7d47b0SAlexander V. Chernikov { 208668394ec8SAlexander V. Chernikov struct ifidx *ifi; 20879f7d47b0SAlexander V. Chernikov 208868394ec8SAlexander V. Chernikov ifi = ifidx_find(ti, key); 20899f7d47b0SAlexander V. Chernikov 209068394ec8SAlexander V. Chernikov if (ifi != NULL) { 209168394ec8SAlexander V. Chernikov *val = ifi->value; 20929f7d47b0SAlexander V. Chernikov return (1); 20939f7d47b0SAlexander V. Chernikov } 20949f7d47b0SAlexander V. Chernikov 20959f7d47b0SAlexander V. Chernikov return (0); 20969f7d47b0SAlexander V. Chernikov } 20979f7d47b0SAlexander V. Chernikov 20989f7d47b0SAlexander V. Chernikov static int 209968394ec8SAlexander V. Chernikov ta_init_ifidx(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti, 2100914bffb6SAlexander V. Chernikov char *data, uint8_t tflags) 21019f7d47b0SAlexander V. Chernikov { 210268394ec8SAlexander V. Chernikov struct iftable_cfg *icfg; 21039f7d47b0SAlexander V. Chernikov 210468394ec8SAlexander V. Chernikov icfg = malloc(sizeof(struct iftable_cfg), M_IPFW, M_WAITOK | M_ZERO); 21059f7d47b0SAlexander V. Chernikov 21060cba2b28SAlexander V. Chernikov icfg->ii = ipfw_objhash_create(DEFAULT_IFIDX_SIZE); 21070cba2b28SAlexander V. Chernikov icfg->size = DEFAULT_IFIDX_SIZE; 21080bce0c23SAlexander V. Chernikov icfg->main_ptr = malloc(sizeof(struct ifidx) * icfg->size, M_IPFW, 210968394ec8SAlexander V. Chernikov M_WAITOK | M_ZERO); 211068394ec8SAlexander V. Chernikov icfg->ch = ch; 21119f7d47b0SAlexander V. Chernikov 211268394ec8SAlexander V. Chernikov *ta_state = icfg; 211368394ec8SAlexander V. Chernikov ti->state = icfg->main_ptr; 211468394ec8SAlexander V. Chernikov ti->lookup = ta_lookup_ifidx; 21159f7d47b0SAlexander V. Chernikov 21169f7d47b0SAlexander V. Chernikov return (0); 21179f7d47b0SAlexander V. Chernikov } 21189f7d47b0SAlexander V. Chernikov 211968394ec8SAlexander V. Chernikov /* 212068394ec8SAlexander V. Chernikov * Handle tableinfo @ti pointer change (on table array resize). 212168394ec8SAlexander V. Chernikov */ 212268394ec8SAlexander V. Chernikov static void 212368394ec8SAlexander V. Chernikov ta_change_ti_ifidx(void *ta_state, struct table_info *ti) 212468394ec8SAlexander V. Chernikov { 212568394ec8SAlexander V. Chernikov struct iftable_cfg *icfg; 212668394ec8SAlexander V. Chernikov 212768394ec8SAlexander V. Chernikov icfg = (struct iftable_cfg *)ta_state; 212868394ec8SAlexander V. Chernikov icfg->ti = ti; 212968394ec8SAlexander V. Chernikov } 21309f7d47b0SAlexander V. Chernikov 2131b309f085SAndrey V. Elsukov static int 213268394ec8SAlexander V. Chernikov destroy_ifidx_locked(struct namedobj_instance *ii, struct named_object *no, 213368394ec8SAlexander V. Chernikov void *arg) 21349f7d47b0SAlexander V. Chernikov { 213568394ec8SAlexander V. Chernikov struct ifentry *ife; 213668394ec8SAlexander V. Chernikov struct ip_fw_chain *ch; 21379f7d47b0SAlexander V. Chernikov 213868394ec8SAlexander V. Chernikov ch = (struct ip_fw_chain *)arg; 213968394ec8SAlexander V. Chernikov ife = (struct ifentry *)no; 214068394ec8SAlexander V. Chernikov 214168394ec8SAlexander V. Chernikov ipfw_iface_del_notify(ch, &ife->ic); 21420caab009SAlexander V. Chernikov ipfw_iface_unref(ch, &ife->ic); 214368394ec8SAlexander V. Chernikov free(ife, M_IPFW_TBL); 2144b309f085SAndrey V. Elsukov return (0); 21459f7d47b0SAlexander V. Chernikov } 21469f7d47b0SAlexander V. Chernikov 214768394ec8SAlexander V. Chernikov 214868394ec8SAlexander V. Chernikov /* 214968394ec8SAlexander V. Chernikov * Destroys table @ti 215068394ec8SAlexander V. Chernikov */ 215168394ec8SAlexander V. Chernikov static void 215268394ec8SAlexander V. Chernikov ta_destroy_ifidx(void *ta_state, struct table_info *ti) 21539f7d47b0SAlexander V. Chernikov { 215468394ec8SAlexander V. Chernikov struct iftable_cfg *icfg; 215568394ec8SAlexander V. Chernikov struct ip_fw_chain *ch; 215668394ec8SAlexander V. Chernikov 215768394ec8SAlexander V. Chernikov icfg = (struct iftable_cfg *)ta_state; 215868394ec8SAlexander V. Chernikov ch = icfg->ch; 215968394ec8SAlexander V. Chernikov 216068394ec8SAlexander V. Chernikov if (icfg->main_ptr != NULL) 216168394ec8SAlexander V. Chernikov free(icfg->main_ptr, M_IPFW); 216268394ec8SAlexander V. Chernikov 21630caab009SAlexander V. Chernikov IPFW_UH_WLOCK(ch); 216468394ec8SAlexander V. Chernikov ipfw_objhash_foreach(icfg->ii, destroy_ifidx_locked, ch); 21650caab009SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 216668394ec8SAlexander V. Chernikov 216768394ec8SAlexander V. Chernikov ipfw_objhash_destroy(icfg->ii); 216868394ec8SAlexander V. Chernikov 216968394ec8SAlexander V. Chernikov free(icfg, M_IPFW); 217068394ec8SAlexander V. Chernikov } 217168394ec8SAlexander V. Chernikov 217268394ec8SAlexander V. Chernikov /* 21735f379342SAlexander V. Chernikov * Provide algo-specific table info 21745f379342SAlexander V. Chernikov */ 21755f379342SAlexander V. Chernikov static void 21765f379342SAlexander V. Chernikov ta_dump_ifidx_tinfo(void *ta_state, struct table_info *ti, ipfw_ta_tinfo *tinfo) 21775f379342SAlexander V. Chernikov { 21785f379342SAlexander V. Chernikov struct iftable_cfg *cfg; 21795f379342SAlexander V. Chernikov 21805f379342SAlexander V. Chernikov cfg = (struct iftable_cfg *)ta_state; 21815f379342SAlexander V. Chernikov 21825f379342SAlexander V. Chernikov tinfo->taclass4 = IPFW_TACLASS_ARRAY; 21835f379342SAlexander V. Chernikov tinfo->size4 = cfg->size; 21845f379342SAlexander V. Chernikov tinfo->count4 = cfg->used; 21855f379342SAlexander V. Chernikov tinfo->itemsize4 = sizeof(struct ifidx); 21865f379342SAlexander V. Chernikov } 21875f379342SAlexander V. Chernikov 21885f379342SAlexander V. Chernikov /* 218968394ec8SAlexander V. Chernikov * Prepare state to add to the table: 219068394ec8SAlexander V. Chernikov * allocate ifentry and reference needed interface. 219168394ec8SAlexander V. Chernikov */ 21929f7d47b0SAlexander V. Chernikov static int 219368394ec8SAlexander V. Chernikov ta_prepare_add_ifidx(struct ip_fw_chain *ch, struct tentry_info *tei, 219468394ec8SAlexander V. Chernikov void *ta_buf) 219568394ec8SAlexander V. Chernikov { 219668394ec8SAlexander V. Chernikov struct ta_buf_ifidx *tb; 219768394ec8SAlexander V. Chernikov char *ifname; 219868394ec8SAlexander V. Chernikov struct ifentry *ife; 219968394ec8SAlexander V. Chernikov 220068394ec8SAlexander V. Chernikov tb = (struct ta_buf_ifidx *)ta_buf; 220168394ec8SAlexander V. Chernikov 220268394ec8SAlexander V. Chernikov /* Check if string is terminated */ 220368394ec8SAlexander V. Chernikov ifname = (char *)tei->paddr; 220468394ec8SAlexander V. Chernikov if (strnlen(ifname, IF_NAMESIZE) == IF_NAMESIZE) 220568394ec8SAlexander V. Chernikov return (EINVAL); 220668394ec8SAlexander V. Chernikov 220768394ec8SAlexander V. Chernikov ife = malloc(sizeof(struct ifentry), M_IPFW_TBL, M_WAITOK | M_ZERO); 220868394ec8SAlexander V. Chernikov ife->ic.cb = if_notifier; 220968394ec8SAlexander V. Chernikov ife->ic.cbdata = ife; 221068394ec8SAlexander V. Chernikov 22118ebca97fSAlexander V. Chernikov if (ipfw_iface_ref(ch, ifname, &ife->ic) != 0) { 22128ebca97fSAlexander V. Chernikov free(ife, M_IPFW_TBL); 221368394ec8SAlexander V. Chernikov return (EINVAL); 22148ebca97fSAlexander V. Chernikov } 221568394ec8SAlexander V. Chernikov 221668394ec8SAlexander V. Chernikov /* Use ipfw_iface 'ifname' field as stable storage */ 221768394ec8SAlexander V. Chernikov ife->no.name = ife->ic.iface->ifname; 221868394ec8SAlexander V. Chernikov 221968394ec8SAlexander V. Chernikov tb->ife = ife; 222068394ec8SAlexander V. Chernikov 222168394ec8SAlexander V. Chernikov return (0); 222268394ec8SAlexander V. Chernikov } 222368394ec8SAlexander V. Chernikov 222468394ec8SAlexander V. Chernikov static int 2225adea6201SAlexander V. Chernikov ta_add_ifidx(void *ta_state, struct table_info *ti, struct tentry_info *tei, 2226b6ee846eSAlexander V. Chernikov void *ta_buf, uint32_t *pnum) 222768394ec8SAlexander V. Chernikov { 222868394ec8SAlexander V. Chernikov struct iftable_cfg *icfg; 222968394ec8SAlexander V. Chernikov struct ifentry *ife, *tmp; 223068394ec8SAlexander V. Chernikov struct ta_buf_ifidx *tb; 223168394ec8SAlexander V. Chernikov struct ipfw_iface *iif; 223268394ec8SAlexander V. Chernikov struct ifidx *ifi; 223368394ec8SAlexander V. Chernikov char *ifname; 2234648e8380SAlexander V. Chernikov uint32_t value; 223568394ec8SAlexander V. Chernikov 223668394ec8SAlexander V. Chernikov tb = (struct ta_buf_ifidx *)ta_buf; 223768394ec8SAlexander V. Chernikov ifname = (char *)tei->paddr; 223868394ec8SAlexander V. Chernikov icfg = (struct iftable_cfg *)ta_state; 223968394ec8SAlexander V. Chernikov ife = tb->ife; 224068394ec8SAlexander V. Chernikov 224168394ec8SAlexander V. Chernikov ife->icfg = icfg; 224213263632SAlexander V. Chernikov ife->value = tei->value; 224368394ec8SAlexander V. Chernikov 224468394ec8SAlexander V. Chernikov tmp = (struct ifentry *)ipfw_objhash_lookup_name(icfg->ii, 0, ifname); 224568394ec8SAlexander V. Chernikov 224668394ec8SAlexander V. Chernikov if (tmp != NULL) { 224768394ec8SAlexander V. Chernikov if ((tei->flags & TEI_FLAGS_UPDATE) == 0) 224868394ec8SAlexander V. Chernikov return (EEXIST); 224968394ec8SAlexander V. Chernikov 2250648e8380SAlexander V. Chernikov /* Exchange values in @tmp and @tei */ 2251648e8380SAlexander V. Chernikov value = tmp->value; 2252648e8380SAlexander V. Chernikov tmp->value = tei->value; 2253648e8380SAlexander V. Chernikov tei->value = value; 225468394ec8SAlexander V. Chernikov 2255648e8380SAlexander V. Chernikov iif = tmp->ic.iface; 225668394ec8SAlexander V. Chernikov if (iif->resolved != 0) { 2257648e8380SAlexander V. Chernikov /* We have to update runtime value, too */ 225868394ec8SAlexander V. Chernikov ifi = ifidx_find(ti, &iif->ifindex); 225968394ec8SAlexander V. Chernikov ifi->value = ife->value; 226068394ec8SAlexander V. Chernikov } 226168394ec8SAlexander V. Chernikov 226268394ec8SAlexander V. Chernikov /* Indicate that update has happened instead of addition */ 226368394ec8SAlexander V. Chernikov tei->flags |= TEI_FLAGS_UPDATED; 2264adea6201SAlexander V. Chernikov *pnum = 0; 226568394ec8SAlexander V. Chernikov return (0); 226668394ec8SAlexander V. Chernikov } 226768394ec8SAlexander V. Chernikov 22684c0c07a5SAlexander V. Chernikov if ((tei->flags & TEI_FLAGS_DONTADD) != 0) 22694c0c07a5SAlexander V. Chernikov return (EFBIG); 22704c0c07a5SAlexander V. Chernikov 227168394ec8SAlexander V. Chernikov /* Link to internal list */ 227268394ec8SAlexander V. Chernikov ipfw_objhash_add(icfg->ii, &ife->no); 227368394ec8SAlexander V. Chernikov 227468394ec8SAlexander V. Chernikov /* Link notifier (possible running its callback) */ 227568394ec8SAlexander V. Chernikov ipfw_iface_add_notify(icfg->ch, &ife->ic); 227668394ec8SAlexander V. Chernikov icfg->count++; 227768394ec8SAlexander V. Chernikov 227868394ec8SAlexander V. Chernikov tb->ife = NULL; 2279adea6201SAlexander V. Chernikov *pnum = 1; 228068394ec8SAlexander V. Chernikov 228168394ec8SAlexander V. Chernikov return (0); 228268394ec8SAlexander V. Chernikov } 228368394ec8SAlexander V. Chernikov 228468394ec8SAlexander V. Chernikov /* 228568394ec8SAlexander V. Chernikov * Prepare to delete key from table. 228668394ec8SAlexander V. Chernikov * Do basic interface name checks. 228768394ec8SAlexander V. Chernikov */ 228868394ec8SAlexander V. Chernikov static int 228968394ec8SAlexander V. Chernikov ta_prepare_del_ifidx(struct ip_fw_chain *ch, struct tentry_info *tei, 229068394ec8SAlexander V. Chernikov void *ta_buf) 22919f7d47b0SAlexander V. Chernikov { 229274b941f0SAlexander V. Chernikov struct ta_buf_ifidx *tb; 2293e0a8b9eeSAlexander V. Chernikov char *ifname; 22949f7d47b0SAlexander V. Chernikov 229574b941f0SAlexander V. Chernikov tb = (struct ta_buf_ifidx *)ta_buf; 22969f7d47b0SAlexander V. Chernikov 22979f7d47b0SAlexander V. Chernikov /* Check if string is terminated */ 2298e0a8b9eeSAlexander V. Chernikov ifname = (char *)tei->paddr; 2299e0a8b9eeSAlexander V. Chernikov if (strnlen(ifname, IF_NAMESIZE) == IF_NAMESIZE) 23009f7d47b0SAlexander V. Chernikov return (EINVAL); 23019f7d47b0SAlexander V. Chernikov 23029f7d47b0SAlexander V. Chernikov return (0); 23039f7d47b0SAlexander V. Chernikov } 23049f7d47b0SAlexander V. Chernikov 230568394ec8SAlexander V. Chernikov /* 230668394ec8SAlexander V. Chernikov * Remove key from both configuration list and 230768394ec8SAlexander V. Chernikov * runtime array. Removed interface notification. 230868394ec8SAlexander V. Chernikov */ 23099f7d47b0SAlexander V. Chernikov static int 2310adea6201SAlexander V. Chernikov ta_del_ifidx(void *ta_state, struct table_info *ti, struct tentry_info *tei, 2311b6ee846eSAlexander V. Chernikov void *ta_buf, uint32_t *pnum) 23129f7d47b0SAlexander V. Chernikov { 231368394ec8SAlexander V. Chernikov struct iftable_cfg *icfg; 231468394ec8SAlexander V. Chernikov struct ifentry *ife; 231568394ec8SAlexander V. Chernikov struct ta_buf_ifidx *tb; 231668394ec8SAlexander V. Chernikov char *ifname; 231768394ec8SAlexander V. Chernikov uint16_t ifindex; 231868394ec8SAlexander V. Chernikov int res; 23199f7d47b0SAlexander V. Chernikov 232068394ec8SAlexander V. Chernikov tb = (struct ta_buf_ifidx *)ta_buf; 232168394ec8SAlexander V. Chernikov ifname = (char *)tei->paddr; 232268394ec8SAlexander V. Chernikov icfg = (struct iftable_cfg *)ta_state; 23239f7d47b0SAlexander V. Chernikov 232468394ec8SAlexander V. Chernikov ife = (struct ifentry *)ipfw_objhash_lookup_name(icfg->ii, 0, ifname); 23259f7d47b0SAlexander V. Chernikov 232668394ec8SAlexander V. Chernikov if (ife == NULL) 232781d3153dSAlexander V. Chernikov return (ENOENT); 23289f7d47b0SAlexander V. Chernikov 232968394ec8SAlexander V. Chernikov if (ife->linked != 0) { 233068394ec8SAlexander V. Chernikov /* We have to remove item from runtime */ 233168394ec8SAlexander V. Chernikov ifindex = ife->ic.iface->ifindex; 233268394ec8SAlexander V. Chernikov 233368394ec8SAlexander V. Chernikov res = bdel(&ifindex, icfg->main_ptr, icfg->used, 233468394ec8SAlexander V. Chernikov sizeof(struct ifidx), compare_ifidx); 233568394ec8SAlexander V. Chernikov 233668394ec8SAlexander V. Chernikov KASSERT(res == 1, ("index %d does not exist", ifindex)); 233768394ec8SAlexander V. Chernikov icfg->used--; 233868394ec8SAlexander V. Chernikov ti->data = icfg->used; 233968394ec8SAlexander V. Chernikov ife->linked = 0; 234068394ec8SAlexander V. Chernikov } 234168394ec8SAlexander V. Chernikov 234268394ec8SAlexander V. Chernikov /* Unlink from local list */ 234368394ec8SAlexander V. Chernikov ipfw_objhash_del(icfg->ii, &ife->no); 23440caab009SAlexander V. Chernikov /* Unlink notifier and deref */ 234568394ec8SAlexander V. Chernikov ipfw_iface_del_notify(icfg->ch, &ife->ic); 23460caab009SAlexander V. Chernikov ipfw_iface_unref(icfg->ch, &ife->ic); 234768394ec8SAlexander V. Chernikov 234868394ec8SAlexander V. Chernikov icfg->count--; 2349648e8380SAlexander V. Chernikov tei->value = ife->value; 235068394ec8SAlexander V. Chernikov 235168394ec8SAlexander V. Chernikov tb->ife = ife; 2352adea6201SAlexander V. Chernikov *pnum = 1; 235368394ec8SAlexander V. Chernikov 23549f7d47b0SAlexander V. Chernikov return (0); 23559f7d47b0SAlexander V. Chernikov } 23569f7d47b0SAlexander V. Chernikov 235768394ec8SAlexander V. Chernikov /* 235868394ec8SAlexander V. Chernikov * Flush deleted entry. 235968394ec8SAlexander V. Chernikov * Drops interface reference and frees entry. 236068394ec8SAlexander V. Chernikov */ 23619f7d47b0SAlexander V. Chernikov static void 236268394ec8SAlexander V. Chernikov ta_flush_ifidx_entry(struct ip_fw_chain *ch, struct tentry_info *tei, 236368394ec8SAlexander V. Chernikov void *ta_buf) 23649f7d47b0SAlexander V. Chernikov { 236568394ec8SAlexander V. Chernikov struct ta_buf_ifidx *tb; 23669f7d47b0SAlexander V. Chernikov 236768394ec8SAlexander V. Chernikov tb = (struct ta_buf_ifidx *)ta_buf; 23689f7d47b0SAlexander V. Chernikov 23690caab009SAlexander V. Chernikov if (tb->ife != NULL) 237068394ec8SAlexander V. Chernikov free(tb->ife, M_IPFW_TBL); 237168394ec8SAlexander V. Chernikov } 237268394ec8SAlexander V. Chernikov 237368394ec8SAlexander V. Chernikov 237468394ec8SAlexander V. Chernikov /* 237568394ec8SAlexander V. Chernikov * Handle interface announce/withdrawal for particular table. 237668394ec8SAlexander V. Chernikov * Every real runtime array modification happens here. 237768394ec8SAlexander V. Chernikov */ 237868394ec8SAlexander V. Chernikov static void 237968394ec8SAlexander V. Chernikov if_notifier(struct ip_fw_chain *ch, void *cbdata, uint16_t ifindex) 238068394ec8SAlexander V. Chernikov { 238168394ec8SAlexander V. Chernikov struct ifentry *ife; 238268394ec8SAlexander V. Chernikov struct ifidx ifi; 238368394ec8SAlexander V. Chernikov struct iftable_cfg *icfg; 238468394ec8SAlexander V. Chernikov struct table_info *ti; 238568394ec8SAlexander V. Chernikov int res; 238668394ec8SAlexander V. Chernikov 238768394ec8SAlexander V. Chernikov ife = (struct ifentry *)cbdata; 238868394ec8SAlexander V. Chernikov icfg = ife->icfg; 238968394ec8SAlexander V. Chernikov ti = icfg->ti; 239068394ec8SAlexander V. Chernikov 239168394ec8SAlexander V. Chernikov KASSERT(ti != NULL, ("ti=NULL, check change_ti handler")); 239268394ec8SAlexander V. Chernikov 239368394ec8SAlexander V. Chernikov if (ife->linked == 0 && ifindex != 0) { 239468394ec8SAlexander V. Chernikov /* Interface announce */ 239568394ec8SAlexander V. Chernikov ifi.kidx = ifindex; 239668394ec8SAlexander V. Chernikov ifi.spare = 0; 239768394ec8SAlexander V. Chernikov ifi.value = ife->value; 239868394ec8SAlexander V. Chernikov res = badd(&ifindex, &ifi, icfg->main_ptr, icfg->used, 239968394ec8SAlexander V. Chernikov sizeof(struct ifidx), compare_ifidx); 240068394ec8SAlexander V. Chernikov KASSERT(res == 1, ("index %d already exists", ifindex)); 240168394ec8SAlexander V. Chernikov icfg->used++; 240268394ec8SAlexander V. Chernikov ti->data = icfg->used; 240368394ec8SAlexander V. Chernikov ife->linked = 1; 240468394ec8SAlexander V. Chernikov } else if (ife->linked != 0 && ifindex == 0) { 240568394ec8SAlexander V. Chernikov /* Interface withdrawal */ 240668394ec8SAlexander V. Chernikov ifindex = ife->ic.iface->ifindex; 240768394ec8SAlexander V. Chernikov 240868394ec8SAlexander V. Chernikov res = bdel(&ifindex, icfg->main_ptr, icfg->used, 240968394ec8SAlexander V. Chernikov sizeof(struct ifidx), compare_ifidx); 241068394ec8SAlexander V. Chernikov 241168394ec8SAlexander V. Chernikov KASSERT(res == 1, ("index %d does not exist", ifindex)); 241268394ec8SAlexander V. Chernikov icfg->used--; 241368394ec8SAlexander V. Chernikov ti->data = icfg->used; 241468394ec8SAlexander V. Chernikov ife->linked = 0; 241568394ec8SAlexander V. Chernikov } 241668394ec8SAlexander V. Chernikov } 241768394ec8SAlexander V. Chernikov 241868394ec8SAlexander V. Chernikov 241968394ec8SAlexander V. Chernikov /* 242068394ec8SAlexander V. Chernikov * Table growing callbacks. 242168394ec8SAlexander V. Chernikov */ 242268394ec8SAlexander V. Chernikov 2423b6ee846eSAlexander V. Chernikov static int 2424301290bcSAlexander V. Chernikov ta_need_modify_ifidx(void *ta_state, struct table_info *ti, uint32_t count, 2425b6ee846eSAlexander V. Chernikov uint64_t *pflags) 2426b6ee846eSAlexander V. Chernikov { 2427b6ee846eSAlexander V. Chernikov struct iftable_cfg *cfg; 24280bce0c23SAlexander V. Chernikov uint32_t size; 2429b6ee846eSAlexander V. Chernikov 2430b6ee846eSAlexander V. Chernikov cfg = (struct iftable_cfg *)ta_state; 2431b6ee846eSAlexander V. Chernikov 24320bce0c23SAlexander V. Chernikov size = cfg->size; 24330bce0c23SAlexander V. Chernikov while (size < cfg->count + count) 24340bce0c23SAlexander V. Chernikov size *= 2; 24350bce0c23SAlexander V. Chernikov 24360bce0c23SAlexander V. Chernikov if (size != cfg->size) { 24370bce0c23SAlexander V. Chernikov *pflags = size; 2438301290bcSAlexander V. Chernikov return (1); 2439b6ee846eSAlexander V. Chernikov } 2440b6ee846eSAlexander V. Chernikov 2441301290bcSAlexander V. Chernikov return (0); 2442b6ee846eSAlexander V. Chernikov } 2443b6ee846eSAlexander V. Chernikov 244468394ec8SAlexander V. Chernikov /* 244568394ec8SAlexander V. Chernikov * Allocate ned, larger runtime ifidx array. 244668394ec8SAlexander V. Chernikov */ 244768394ec8SAlexander V. Chernikov static int 244868394ec8SAlexander V. Chernikov ta_prepare_mod_ifidx(void *ta_buf, uint64_t *pflags) 244968394ec8SAlexander V. Chernikov { 24500bce0c23SAlexander V. Chernikov struct mod_item *mi; 245168394ec8SAlexander V. Chernikov 24520bce0c23SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 245368394ec8SAlexander V. Chernikov 24540bce0c23SAlexander V. Chernikov memset(mi, 0, sizeof(struct mod_item)); 245568394ec8SAlexander V. Chernikov mi->size = *pflags; 245668394ec8SAlexander V. Chernikov mi->main_ptr = malloc(sizeof(struct ifidx) * mi->size, M_IPFW, 245768394ec8SAlexander V. Chernikov M_WAITOK | M_ZERO); 245868394ec8SAlexander V. Chernikov 245968394ec8SAlexander V. Chernikov return (0); 246068394ec8SAlexander V. Chernikov } 246168394ec8SAlexander V. Chernikov 246268394ec8SAlexander V. Chernikov /* 246368394ec8SAlexander V. Chernikov * Copy data from old runtime array to new one. 246468394ec8SAlexander V. Chernikov */ 246568394ec8SAlexander V. Chernikov static int 246668394ec8SAlexander V. Chernikov ta_fill_mod_ifidx(void *ta_state, struct table_info *ti, void *ta_buf, 246768394ec8SAlexander V. Chernikov uint64_t *pflags) 246868394ec8SAlexander V. Chernikov { 24690bce0c23SAlexander V. Chernikov struct mod_item *mi; 247068394ec8SAlexander V. Chernikov struct iftable_cfg *icfg; 247168394ec8SAlexander V. Chernikov 24720bce0c23SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 247368394ec8SAlexander V. Chernikov icfg = (struct iftable_cfg *)ta_state; 247468394ec8SAlexander V. Chernikov 247568394ec8SAlexander V. Chernikov /* Check if we still need to grow array */ 247668394ec8SAlexander V. Chernikov if (icfg->size >= mi->size) { 247768394ec8SAlexander V. Chernikov *pflags = 0; 247868394ec8SAlexander V. Chernikov return (0); 247968394ec8SAlexander V. Chernikov } 248068394ec8SAlexander V. Chernikov 248168394ec8SAlexander V. Chernikov memcpy(mi->main_ptr, icfg->main_ptr, icfg->used * sizeof(struct ifidx)); 248268394ec8SAlexander V. Chernikov 248368394ec8SAlexander V. Chernikov return (0); 248468394ec8SAlexander V. Chernikov } 248568394ec8SAlexander V. Chernikov 248668394ec8SAlexander V. Chernikov /* 248768394ec8SAlexander V. Chernikov * Switch old & new arrays. 248868394ec8SAlexander V. Chernikov */ 2489301290bcSAlexander V. Chernikov static void 249068394ec8SAlexander V. Chernikov ta_modify_ifidx(void *ta_state, struct table_info *ti, void *ta_buf, 249168394ec8SAlexander V. Chernikov uint64_t pflags) 249268394ec8SAlexander V. Chernikov { 24930bce0c23SAlexander V. Chernikov struct mod_item *mi; 249468394ec8SAlexander V. Chernikov struct iftable_cfg *icfg; 249568394ec8SAlexander V. Chernikov void *old_ptr; 249668394ec8SAlexander V. Chernikov 24970bce0c23SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 249868394ec8SAlexander V. Chernikov icfg = (struct iftable_cfg *)ta_state; 249968394ec8SAlexander V. Chernikov 250068394ec8SAlexander V. Chernikov old_ptr = icfg->main_ptr; 250168394ec8SAlexander V. Chernikov icfg->main_ptr = mi->main_ptr; 250268394ec8SAlexander V. Chernikov icfg->size = mi->size; 250368394ec8SAlexander V. Chernikov ti->state = icfg->main_ptr; 250468394ec8SAlexander V. Chernikov 250568394ec8SAlexander V. Chernikov mi->main_ptr = old_ptr; 250668394ec8SAlexander V. Chernikov } 250768394ec8SAlexander V. Chernikov 250868394ec8SAlexander V. Chernikov /* 250968394ec8SAlexander V. Chernikov * Free unneded array. 251068394ec8SAlexander V. Chernikov */ 251168394ec8SAlexander V. Chernikov static void 251268394ec8SAlexander V. Chernikov ta_flush_mod_ifidx(void *ta_buf) 251368394ec8SAlexander V. Chernikov { 25140bce0c23SAlexander V. Chernikov struct mod_item *mi; 251568394ec8SAlexander V. Chernikov 25160bce0c23SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 251768394ec8SAlexander V. Chernikov if (mi->main_ptr != NULL) 251868394ec8SAlexander V. Chernikov free(mi->main_ptr, M_IPFW); 25199f7d47b0SAlexander V. Chernikov } 25209f7d47b0SAlexander V. Chernikov 25219f7d47b0SAlexander V. Chernikov static int 252268394ec8SAlexander V. Chernikov ta_dump_ifidx_tentry(void *ta_state, struct table_info *ti, void *e, 252381d3153dSAlexander V. Chernikov ipfw_obj_tentry *tent) 25249f7d47b0SAlexander V. Chernikov { 252568394ec8SAlexander V. Chernikov struct ifentry *ife; 25269f7d47b0SAlexander V. Chernikov 252768394ec8SAlexander V. Chernikov ife = (struct ifentry *)e; 252868394ec8SAlexander V. Chernikov 252981d3153dSAlexander V. Chernikov tent->masklen = 8 * IF_NAMESIZE; 253068394ec8SAlexander V. Chernikov memcpy(&tent->k, ife->no.name, IF_NAMESIZE); 25310cba2b28SAlexander V. Chernikov tent->v.kidx = ife->value; 25329f7d47b0SAlexander V. Chernikov 25339f7d47b0SAlexander V. Chernikov return (0); 25349f7d47b0SAlexander V. Chernikov } 25359f7d47b0SAlexander V. Chernikov 253681d3153dSAlexander V. Chernikov static int 2537914bffb6SAlexander V. Chernikov ta_find_ifidx_tentry(void *ta_state, struct table_info *ti, 2538914bffb6SAlexander V. Chernikov ipfw_obj_tentry *tent) 253981d3153dSAlexander V. Chernikov { 254068394ec8SAlexander V. Chernikov struct iftable_cfg *icfg; 254168394ec8SAlexander V. Chernikov struct ifentry *ife; 254268394ec8SAlexander V. Chernikov char *ifname; 254381d3153dSAlexander V. Chernikov 254468394ec8SAlexander V. Chernikov icfg = (struct iftable_cfg *)ta_state; 2545914bffb6SAlexander V. Chernikov ifname = tent->k.iface; 254681d3153dSAlexander V. Chernikov 254768394ec8SAlexander V. Chernikov if (strnlen(ifname, IF_NAMESIZE) == IF_NAMESIZE) 254868394ec8SAlexander V. Chernikov return (EINVAL); 254981d3153dSAlexander V. Chernikov 255068394ec8SAlexander V. Chernikov ife = (struct ifentry *)ipfw_objhash_lookup_name(icfg->ii, 0, ifname); 255168394ec8SAlexander V. Chernikov 255268394ec8SAlexander V. Chernikov if (ife != NULL) { 255368394ec8SAlexander V. Chernikov ta_dump_ifidx_tentry(ta_state, ti, ife, tent); 255481d3153dSAlexander V. Chernikov return (0); 255581d3153dSAlexander V. Chernikov } 255681d3153dSAlexander V. Chernikov 255781d3153dSAlexander V. Chernikov return (ENOENT); 255881d3153dSAlexander V. Chernikov } 255981d3153dSAlexander V. Chernikov 256068394ec8SAlexander V. Chernikov struct wa_ifidx { 256168394ec8SAlexander V. Chernikov ta_foreach_f *f; 256268394ec8SAlexander V. Chernikov void *arg; 256368394ec8SAlexander V. Chernikov }; 256468394ec8SAlexander V. Chernikov 2565b309f085SAndrey V. Elsukov static int 256668394ec8SAlexander V. Chernikov foreach_ifidx(struct namedobj_instance *ii, struct named_object *no, 25679f7d47b0SAlexander V. Chernikov void *arg) 25689f7d47b0SAlexander V. Chernikov { 256968394ec8SAlexander V. Chernikov struct ifentry *ife; 257068394ec8SAlexander V. Chernikov struct wa_ifidx *wa; 25719f7d47b0SAlexander V. Chernikov 257268394ec8SAlexander V. Chernikov ife = (struct ifentry *)no; 257368394ec8SAlexander V. Chernikov wa = (struct wa_ifidx *)arg; 257468394ec8SAlexander V. Chernikov 257568394ec8SAlexander V. Chernikov wa->f(ife, wa->arg); 2576b309f085SAndrey V. Elsukov return (0); 25779f7d47b0SAlexander V. Chernikov } 25789f7d47b0SAlexander V. Chernikov 257968394ec8SAlexander V. Chernikov static void 258068394ec8SAlexander V. Chernikov ta_foreach_ifidx(void *ta_state, struct table_info *ti, ta_foreach_f *f, 258168394ec8SAlexander V. Chernikov void *arg) 258268394ec8SAlexander V. Chernikov { 258368394ec8SAlexander V. Chernikov struct iftable_cfg *icfg; 258468394ec8SAlexander V. Chernikov struct wa_ifidx wa; 258568394ec8SAlexander V. Chernikov 258668394ec8SAlexander V. Chernikov icfg = (struct iftable_cfg *)ta_state; 258768394ec8SAlexander V. Chernikov 258868394ec8SAlexander V. Chernikov wa.f = f; 258968394ec8SAlexander V. Chernikov wa.arg = arg; 259068394ec8SAlexander V. Chernikov 259168394ec8SAlexander V. Chernikov ipfw_objhash_foreach(icfg->ii, foreach_ifidx, &wa); 259268394ec8SAlexander V. Chernikov } 259368394ec8SAlexander V. Chernikov 259474b941f0SAlexander V. Chernikov struct table_algo iface_idx = { 2595adea6201SAlexander V. Chernikov .name = "iface:array", 25969d099b4fSAlexander V. Chernikov .type = IPFW_TABLE_INTERFACE, 259757a1cf95SAlexander V. Chernikov .flags = TA_FLAG_DEFAULT, 259857a1cf95SAlexander V. Chernikov .ta_buf_size = sizeof(struct ta_buf_ifidx), 259968394ec8SAlexander V. Chernikov .init = ta_init_ifidx, 260068394ec8SAlexander V. Chernikov .destroy = ta_destroy_ifidx, 260168394ec8SAlexander V. Chernikov .prepare_add = ta_prepare_add_ifidx, 260268394ec8SAlexander V. Chernikov .prepare_del = ta_prepare_del_ifidx, 260368394ec8SAlexander V. Chernikov .add = ta_add_ifidx, 260468394ec8SAlexander V. Chernikov .del = ta_del_ifidx, 260568394ec8SAlexander V. Chernikov .flush_entry = ta_flush_ifidx_entry, 260668394ec8SAlexander V. Chernikov .foreach = ta_foreach_ifidx, 260768394ec8SAlexander V. Chernikov .dump_tentry = ta_dump_ifidx_tentry, 260868394ec8SAlexander V. Chernikov .find_tentry = ta_find_ifidx_tentry, 26095f379342SAlexander V. Chernikov .dump_tinfo = ta_dump_ifidx_tinfo, 2610301290bcSAlexander V. Chernikov .need_modify = ta_need_modify_ifidx, 261168394ec8SAlexander V. Chernikov .prepare_mod = ta_prepare_mod_ifidx, 261268394ec8SAlexander V. Chernikov .fill_mod = ta_fill_mod_ifidx, 261368394ec8SAlexander V. Chernikov .modify = ta_modify_ifidx, 261468394ec8SAlexander V. Chernikov .flush_mod = ta_flush_mod_ifidx, 261568394ec8SAlexander V. Chernikov .change_ti = ta_change_ti_ifidx, 26169f7d47b0SAlexander V. Chernikov }; 26179f7d47b0SAlexander V. Chernikov 2618b23d5de9SAlexander V. Chernikov /* 2619b23d5de9SAlexander V. Chernikov * Number array cmds. 2620b23d5de9SAlexander V. Chernikov * 2621b23d5de9SAlexander V. Chernikov * Implementation: 2622b23d5de9SAlexander V. Chernikov * 2623b23d5de9SAlexander V. Chernikov * Runtime part: 2624b23d5de9SAlexander V. Chernikov * - sorted array of "struct numarray" pointed by ti->state. 2625b23d5de9SAlexander V. Chernikov * Array is allocated with rounding up to NUMARRAY_CHUNK. 2626b23d5de9SAlexander V. Chernikov * - current array size is stored in ti->data 2627b23d5de9SAlexander V. Chernikov * 2628b23d5de9SAlexander V. Chernikov */ 2629b23d5de9SAlexander V. Chernikov 2630b23d5de9SAlexander V. Chernikov struct numarray { 2631b23d5de9SAlexander V. Chernikov uint32_t number; 2632b23d5de9SAlexander V. Chernikov uint32_t value; 2633b23d5de9SAlexander V. Chernikov }; 2634b23d5de9SAlexander V. Chernikov 2635b23d5de9SAlexander V. Chernikov struct numarray_cfg { 2636b23d5de9SAlexander V. Chernikov void *main_ptr; 2637b23d5de9SAlexander V. Chernikov size_t size; /* Number of items allocated in array */ 2638b23d5de9SAlexander V. Chernikov size_t used; /* Number of items _active_ now */ 2639b23d5de9SAlexander V. Chernikov }; 2640b23d5de9SAlexander V. Chernikov 26410bce0c23SAlexander V. Chernikov struct ta_buf_numarray 26420bce0c23SAlexander V. Chernikov { 26430bce0c23SAlexander V. Chernikov struct numarray na; 26440bce0c23SAlexander V. Chernikov }; 2645b23d5de9SAlexander V. Chernikov 2646b23d5de9SAlexander V. Chernikov int compare_numarray(const void *k, const void *v); 26479fe15d06SAlexander V. Chernikov static struct numarray *numarray_find(struct table_info *ti, void *key); 26489fe15d06SAlexander V. Chernikov static int ta_lookup_numarray(struct table_info *ti, void *key, 26499fe15d06SAlexander V. Chernikov uint32_t keylen, uint32_t *val); 26509fe15d06SAlexander V. Chernikov static int ta_init_numarray(struct ip_fw_chain *ch, void **ta_state, 26519fe15d06SAlexander V. Chernikov struct table_info *ti, char *data, uint8_t tflags); 26529fe15d06SAlexander V. Chernikov static void ta_destroy_numarray(void *ta_state, struct table_info *ti); 26539fe15d06SAlexander V. Chernikov static void ta_dump_numarray_tinfo(void *ta_state, struct table_info *ti, 26549fe15d06SAlexander V. Chernikov ipfw_ta_tinfo *tinfo); 26559fe15d06SAlexander V. Chernikov static int ta_prepare_add_numarray(struct ip_fw_chain *ch, 26569fe15d06SAlexander V. Chernikov struct tentry_info *tei, void *ta_buf); 26579fe15d06SAlexander V. Chernikov static int ta_add_numarray(void *ta_state, struct table_info *ti, 26589fe15d06SAlexander V. Chernikov struct tentry_info *tei, void *ta_buf, uint32_t *pnum); 26599fe15d06SAlexander V. Chernikov static int ta_del_numarray(void *ta_state, struct table_info *ti, 26609fe15d06SAlexander V. Chernikov struct tentry_info *tei, void *ta_buf, uint32_t *pnum); 26619fe15d06SAlexander V. Chernikov static void ta_flush_numarray_entry(struct ip_fw_chain *ch, 26629fe15d06SAlexander V. Chernikov struct tentry_info *tei, void *ta_buf); 26639fe15d06SAlexander V. Chernikov static int ta_need_modify_numarray(void *ta_state, struct table_info *ti, 26649fe15d06SAlexander V. Chernikov uint32_t count, uint64_t *pflags); 26659fe15d06SAlexander V. Chernikov static int ta_prepare_mod_numarray(void *ta_buf, uint64_t *pflags); 26669fe15d06SAlexander V. Chernikov static int ta_fill_mod_numarray(void *ta_state, struct table_info *ti, 26679fe15d06SAlexander V. Chernikov void *ta_buf, uint64_t *pflags); 26689fe15d06SAlexander V. Chernikov static void ta_modify_numarray(void *ta_state, struct table_info *ti, 26699fe15d06SAlexander V. Chernikov void *ta_buf, uint64_t pflags); 26709fe15d06SAlexander V. Chernikov static void ta_flush_mod_numarray(void *ta_buf); 26719fe15d06SAlexander V. Chernikov static int ta_dump_numarray_tentry(void *ta_state, struct table_info *ti, 26729fe15d06SAlexander V. Chernikov void *e, ipfw_obj_tentry *tent); 26739fe15d06SAlexander V. Chernikov static int ta_find_numarray_tentry(void *ta_state, struct table_info *ti, 26749fe15d06SAlexander V. Chernikov ipfw_obj_tentry *tent); 26759fe15d06SAlexander V. Chernikov static void ta_foreach_numarray(void *ta_state, struct table_info *ti, 26769fe15d06SAlexander V. Chernikov ta_foreach_f *f, void *arg); 2677b23d5de9SAlexander V. Chernikov 2678b23d5de9SAlexander V. Chernikov int 2679b23d5de9SAlexander V. Chernikov compare_numarray(const void *k, const void *v) 2680b23d5de9SAlexander V. Chernikov { 2681d4e1b515SAlexander V. Chernikov const struct numarray *na; 2682b23d5de9SAlexander V. Chernikov uint32_t key; 2683b23d5de9SAlexander V. Chernikov 2684d4e1b515SAlexander V. Chernikov key = *((const uint32_t *)k); 2685d4e1b515SAlexander V. Chernikov na = (const struct numarray *)v; 2686b23d5de9SAlexander V. Chernikov 2687b23d5de9SAlexander V. Chernikov if (key < na->number) 2688b23d5de9SAlexander V. Chernikov return (-1); 2689b23d5de9SAlexander V. Chernikov else if (key > na->number) 2690b23d5de9SAlexander V. Chernikov return (1); 2691b23d5de9SAlexander V. Chernikov 2692b23d5de9SAlexander V. Chernikov return (0); 2693b23d5de9SAlexander V. Chernikov } 2694b23d5de9SAlexander V. Chernikov 2695b23d5de9SAlexander V. Chernikov static struct numarray * 2696b23d5de9SAlexander V. Chernikov numarray_find(struct table_info *ti, void *key) 2697b23d5de9SAlexander V. Chernikov { 2698b23d5de9SAlexander V. Chernikov struct numarray *ri; 2699b23d5de9SAlexander V. Chernikov 2700b23d5de9SAlexander V. Chernikov ri = bsearch(key, ti->state, ti->data, sizeof(struct numarray), 2701b23d5de9SAlexander V. Chernikov compare_ifidx); 2702b23d5de9SAlexander V. Chernikov 2703b23d5de9SAlexander V. Chernikov return (ri); 2704b23d5de9SAlexander V. Chernikov } 2705b23d5de9SAlexander V. Chernikov 2706b23d5de9SAlexander V. Chernikov static int 2707b23d5de9SAlexander V. Chernikov ta_lookup_numarray(struct table_info *ti, void *key, uint32_t keylen, 2708b23d5de9SAlexander V. Chernikov uint32_t *val) 2709b23d5de9SAlexander V. Chernikov { 2710b23d5de9SAlexander V. Chernikov struct numarray *ri; 2711b23d5de9SAlexander V. Chernikov 2712b23d5de9SAlexander V. Chernikov ri = numarray_find(ti, key); 2713b23d5de9SAlexander V. Chernikov 2714b23d5de9SAlexander V. Chernikov if (ri != NULL) { 2715b23d5de9SAlexander V. Chernikov *val = ri->value; 2716b23d5de9SAlexander V. Chernikov return (1); 2717b23d5de9SAlexander V. Chernikov } 2718b23d5de9SAlexander V. Chernikov 2719b23d5de9SAlexander V. Chernikov return (0); 2720b23d5de9SAlexander V. Chernikov } 2721b23d5de9SAlexander V. Chernikov 2722b23d5de9SAlexander V. Chernikov static int 2723b23d5de9SAlexander V. Chernikov ta_init_numarray(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti, 2724914bffb6SAlexander V. Chernikov char *data, uint8_t tflags) 2725b23d5de9SAlexander V. Chernikov { 2726b23d5de9SAlexander V. Chernikov struct numarray_cfg *cfg; 2727b23d5de9SAlexander V. Chernikov 2728b23d5de9SAlexander V. Chernikov cfg = malloc(sizeof(*cfg), M_IPFW, M_WAITOK | M_ZERO); 2729b23d5de9SAlexander V. Chernikov 27300bce0c23SAlexander V. Chernikov cfg->size = 16; 2731b23d5de9SAlexander V. Chernikov cfg->main_ptr = malloc(sizeof(struct numarray) * cfg->size, M_IPFW, 2732b23d5de9SAlexander V. Chernikov M_WAITOK | M_ZERO); 2733b23d5de9SAlexander V. Chernikov 2734b23d5de9SAlexander V. Chernikov *ta_state = cfg; 2735b23d5de9SAlexander V. Chernikov ti->state = cfg->main_ptr; 2736b23d5de9SAlexander V. Chernikov ti->lookup = ta_lookup_numarray; 2737b23d5de9SAlexander V. Chernikov 2738b23d5de9SAlexander V. Chernikov return (0); 2739b23d5de9SAlexander V. Chernikov } 2740b23d5de9SAlexander V. Chernikov 2741b23d5de9SAlexander V. Chernikov /* 2742b23d5de9SAlexander V. Chernikov * Destroys table @ti 2743b23d5de9SAlexander V. Chernikov */ 2744b23d5de9SAlexander V. Chernikov static void 2745b23d5de9SAlexander V. Chernikov ta_destroy_numarray(void *ta_state, struct table_info *ti) 2746b23d5de9SAlexander V. Chernikov { 2747b23d5de9SAlexander V. Chernikov struct numarray_cfg *cfg; 2748b23d5de9SAlexander V. Chernikov 2749b23d5de9SAlexander V. Chernikov cfg = (struct numarray_cfg *)ta_state; 2750b23d5de9SAlexander V. Chernikov 2751b23d5de9SAlexander V. Chernikov if (cfg->main_ptr != NULL) 2752b23d5de9SAlexander V. Chernikov free(cfg->main_ptr, M_IPFW); 2753b23d5de9SAlexander V. Chernikov 2754b23d5de9SAlexander V. Chernikov free(cfg, M_IPFW); 2755b23d5de9SAlexander V. Chernikov } 2756b23d5de9SAlexander V. Chernikov 2757b23d5de9SAlexander V. Chernikov /* 27585f379342SAlexander V. Chernikov * Provide algo-specific table info 27595f379342SAlexander V. Chernikov */ 27605f379342SAlexander V. Chernikov static void 27615f379342SAlexander V. Chernikov ta_dump_numarray_tinfo(void *ta_state, struct table_info *ti, ipfw_ta_tinfo *tinfo) 27625f379342SAlexander V. Chernikov { 27635f379342SAlexander V. Chernikov struct numarray_cfg *cfg; 27645f379342SAlexander V. Chernikov 27655f379342SAlexander V. Chernikov cfg = (struct numarray_cfg *)ta_state; 27665f379342SAlexander V. Chernikov 27675f379342SAlexander V. Chernikov tinfo->taclass4 = IPFW_TACLASS_ARRAY; 27685f379342SAlexander V. Chernikov tinfo->size4 = cfg->size; 27695f379342SAlexander V. Chernikov tinfo->count4 = cfg->used; 27705f379342SAlexander V. Chernikov tinfo->itemsize4 = sizeof(struct numarray); 27715f379342SAlexander V. Chernikov } 27725f379342SAlexander V. Chernikov 27735f379342SAlexander V. Chernikov /* 2774b23d5de9SAlexander V. Chernikov * Prepare for addition/deletion to an array. 2775b23d5de9SAlexander V. Chernikov */ 2776b23d5de9SAlexander V. Chernikov static int 2777b23d5de9SAlexander V. Chernikov ta_prepare_add_numarray(struct ip_fw_chain *ch, struct tentry_info *tei, 2778b23d5de9SAlexander V. Chernikov void *ta_buf) 2779b23d5de9SAlexander V. Chernikov { 2780b23d5de9SAlexander V. Chernikov struct ta_buf_numarray *tb; 2781b23d5de9SAlexander V. Chernikov 2782b23d5de9SAlexander V. Chernikov tb = (struct ta_buf_numarray *)ta_buf; 2783b23d5de9SAlexander V. Chernikov 2784b23d5de9SAlexander V. Chernikov tb->na.number = *((uint32_t *)tei->paddr); 2785b23d5de9SAlexander V. Chernikov 2786b23d5de9SAlexander V. Chernikov return (0); 2787b23d5de9SAlexander V. Chernikov } 2788b23d5de9SAlexander V. Chernikov 2789b23d5de9SAlexander V. Chernikov static int 2790b23d5de9SAlexander V. Chernikov ta_add_numarray(void *ta_state, struct table_info *ti, struct tentry_info *tei, 2791b6ee846eSAlexander V. Chernikov void *ta_buf, uint32_t *pnum) 2792b23d5de9SAlexander V. Chernikov { 2793b23d5de9SAlexander V. Chernikov struct numarray_cfg *cfg; 2794b23d5de9SAlexander V. Chernikov struct ta_buf_numarray *tb; 2795b23d5de9SAlexander V. Chernikov struct numarray *ri; 2796b23d5de9SAlexander V. Chernikov int res; 2797648e8380SAlexander V. Chernikov uint32_t value; 2798b23d5de9SAlexander V. Chernikov 2799b23d5de9SAlexander V. Chernikov tb = (struct ta_buf_numarray *)ta_buf; 2800b23d5de9SAlexander V. Chernikov cfg = (struct numarray_cfg *)ta_state; 2801b23d5de9SAlexander V. Chernikov 280213263632SAlexander V. Chernikov /* Read current value from @tei */ 280313263632SAlexander V. Chernikov tb->na.value = tei->value; 280413263632SAlexander V. Chernikov 2805b23d5de9SAlexander V. Chernikov ri = numarray_find(ti, &tb->na.number); 2806b23d5de9SAlexander V. Chernikov 2807b23d5de9SAlexander V. Chernikov if (ri != NULL) { 2808b23d5de9SAlexander V. Chernikov if ((tei->flags & TEI_FLAGS_UPDATE) == 0) 2809b23d5de9SAlexander V. Chernikov return (EEXIST); 2810b23d5de9SAlexander V. Chernikov 2811648e8380SAlexander V. Chernikov /* Exchange values between ri and @tei */ 2812648e8380SAlexander V. Chernikov value = ri->value; 2813648e8380SAlexander V. Chernikov ri->value = tei->value; 2814648e8380SAlexander V. Chernikov tei->value = value; 2815b23d5de9SAlexander V. Chernikov /* Indicate that update has happened instead of addition */ 2816b23d5de9SAlexander V. Chernikov tei->flags |= TEI_FLAGS_UPDATED; 2817b23d5de9SAlexander V. Chernikov *pnum = 0; 2818b23d5de9SAlexander V. Chernikov return (0); 2819b23d5de9SAlexander V. Chernikov } 2820b23d5de9SAlexander V. Chernikov 28214c0c07a5SAlexander V. Chernikov if ((tei->flags & TEI_FLAGS_DONTADD) != 0) 28224c0c07a5SAlexander V. Chernikov return (EFBIG); 28234c0c07a5SAlexander V. Chernikov 2824b23d5de9SAlexander V. Chernikov res = badd(&tb->na.number, &tb->na, cfg->main_ptr, cfg->used, 2825b23d5de9SAlexander V. Chernikov sizeof(struct numarray), compare_numarray); 2826b23d5de9SAlexander V. Chernikov 2827b23d5de9SAlexander V. Chernikov KASSERT(res == 1, ("number %d already exists", tb->na.number)); 2828b23d5de9SAlexander V. Chernikov cfg->used++; 2829b23d5de9SAlexander V. Chernikov ti->data = cfg->used; 2830b23d5de9SAlexander V. Chernikov *pnum = 1; 2831b23d5de9SAlexander V. Chernikov 2832b23d5de9SAlexander V. Chernikov return (0); 2833b23d5de9SAlexander V. Chernikov } 2834b23d5de9SAlexander V. Chernikov 2835b23d5de9SAlexander V. Chernikov /* 2836b23d5de9SAlexander V. Chernikov * Remove key from both configuration list and 2837b23d5de9SAlexander V. Chernikov * runtime array. Removed interface notification. 2838b23d5de9SAlexander V. Chernikov */ 2839b23d5de9SAlexander V. Chernikov static int 2840b23d5de9SAlexander V. Chernikov ta_del_numarray(void *ta_state, struct table_info *ti, struct tentry_info *tei, 2841b6ee846eSAlexander V. Chernikov void *ta_buf, uint32_t *pnum) 2842b23d5de9SAlexander V. Chernikov { 2843b23d5de9SAlexander V. Chernikov struct numarray_cfg *cfg; 2844b23d5de9SAlexander V. Chernikov struct ta_buf_numarray *tb; 2845b23d5de9SAlexander V. Chernikov struct numarray *ri; 2846b23d5de9SAlexander V. Chernikov int res; 2847b23d5de9SAlexander V. Chernikov 2848b23d5de9SAlexander V. Chernikov tb = (struct ta_buf_numarray *)ta_buf; 2849b23d5de9SAlexander V. Chernikov cfg = (struct numarray_cfg *)ta_state; 2850b23d5de9SAlexander V. Chernikov 2851b23d5de9SAlexander V. Chernikov ri = numarray_find(ti, &tb->na.number); 2852b23d5de9SAlexander V. Chernikov if (ri == NULL) 2853b23d5de9SAlexander V. Chernikov return (ENOENT); 2854b23d5de9SAlexander V. Chernikov 2855648e8380SAlexander V. Chernikov tei->value = ri->value; 2856648e8380SAlexander V. Chernikov 2857b23d5de9SAlexander V. Chernikov res = bdel(&tb->na.number, cfg->main_ptr, cfg->used, 2858b23d5de9SAlexander V. Chernikov sizeof(struct numarray), compare_numarray); 2859b23d5de9SAlexander V. Chernikov 2860b23d5de9SAlexander V. Chernikov KASSERT(res == 1, ("number %u does not exist", tb->na.number)); 2861b23d5de9SAlexander V. Chernikov cfg->used--; 2862b23d5de9SAlexander V. Chernikov ti->data = cfg->used; 2863b23d5de9SAlexander V. Chernikov *pnum = 1; 2864b23d5de9SAlexander V. Chernikov 2865b23d5de9SAlexander V. Chernikov return (0); 2866b23d5de9SAlexander V. Chernikov } 2867b23d5de9SAlexander V. Chernikov 2868b23d5de9SAlexander V. Chernikov static void 2869b23d5de9SAlexander V. Chernikov ta_flush_numarray_entry(struct ip_fw_chain *ch, struct tentry_info *tei, 2870b23d5de9SAlexander V. Chernikov void *ta_buf) 2871b23d5de9SAlexander V. Chernikov { 2872b23d5de9SAlexander V. Chernikov 28730bce0c23SAlexander V. Chernikov /* We don't have any state, do nothing */ 2874b23d5de9SAlexander V. Chernikov } 2875b23d5de9SAlexander V. Chernikov 2876b23d5de9SAlexander V. Chernikov 2877b23d5de9SAlexander V. Chernikov /* 2878b23d5de9SAlexander V. Chernikov * Table growing callbacks. 2879b23d5de9SAlexander V. Chernikov */ 2880b23d5de9SAlexander V. Chernikov 2881b6ee846eSAlexander V. Chernikov static int 2882301290bcSAlexander V. Chernikov ta_need_modify_numarray(void *ta_state, struct table_info *ti, uint32_t count, 2883b6ee846eSAlexander V. Chernikov uint64_t *pflags) 2884b6ee846eSAlexander V. Chernikov { 2885b6ee846eSAlexander V. Chernikov struct numarray_cfg *cfg; 28860bce0c23SAlexander V. Chernikov size_t size; 2887b6ee846eSAlexander V. Chernikov 2888b6ee846eSAlexander V. Chernikov cfg = (struct numarray_cfg *)ta_state; 2889b6ee846eSAlexander V. Chernikov 28900bce0c23SAlexander V. Chernikov size = cfg->size; 28910bce0c23SAlexander V. Chernikov while (size < cfg->used + count) 28920bce0c23SAlexander V. Chernikov size *= 2; 28930bce0c23SAlexander V. Chernikov 28940bce0c23SAlexander V. Chernikov if (size != cfg->size) { 28950bce0c23SAlexander V. Chernikov *pflags = size; 2896301290bcSAlexander V. Chernikov return (1); 2897b6ee846eSAlexander V. Chernikov } 2898b6ee846eSAlexander V. Chernikov 2899301290bcSAlexander V. Chernikov return (0); 2900b6ee846eSAlexander V. Chernikov } 2901b6ee846eSAlexander V. Chernikov 2902b23d5de9SAlexander V. Chernikov /* 2903b6ee846eSAlexander V. Chernikov * Allocate new, larger runtime array. 2904b23d5de9SAlexander V. Chernikov */ 2905b23d5de9SAlexander V. Chernikov static int 2906b23d5de9SAlexander V. Chernikov ta_prepare_mod_numarray(void *ta_buf, uint64_t *pflags) 2907b23d5de9SAlexander V. Chernikov { 2908b23d5de9SAlexander V. Chernikov struct mod_item *mi; 2909b23d5de9SAlexander V. Chernikov 2910b23d5de9SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 2911b23d5de9SAlexander V. Chernikov 2912b23d5de9SAlexander V. Chernikov memset(mi, 0, sizeof(struct mod_item)); 2913b23d5de9SAlexander V. Chernikov mi->size = *pflags; 2914b23d5de9SAlexander V. Chernikov mi->main_ptr = malloc(sizeof(struct numarray) * mi->size, M_IPFW, 2915b23d5de9SAlexander V. Chernikov M_WAITOK | M_ZERO); 2916b23d5de9SAlexander V. Chernikov 2917b23d5de9SAlexander V. Chernikov return (0); 2918b23d5de9SAlexander V. Chernikov } 2919b23d5de9SAlexander V. Chernikov 2920b23d5de9SAlexander V. Chernikov /* 2921b23d5de9SAlexander V. Chernikov * Copy data from old runtime array to new one. 2922b23d5de9SAlexander V. Chernikov */ 2923b23d5de9SAlexander V. Chernikov static int 2924b23d5de9SAlexander V. Chernikov ta_fill_mod_numarray(void *ta_state, struct table_info *ti, void *ta_buf, 2925b23d5de9SAlexander V. Chernikov uint64_t *pflags) 2926b23d5de9SAlexander V. Chernikov { 2927b23d5de9SAlexander V. Chernikov struct mod_item *mi; 2928b23d5de9SAlexander V. Chernikov struct numarray_cfg *cfg; 2929b23d5de9SAlexander V. Chernikov 2930b23d5de9SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 2931b23d5de9SAlexander V. Chernikov cfg = (struct numarray_cfg *)ta_state; 2932b23d5de9SAlexander V. Chernikov 2933b23d5de9SAlexander V. Chernikov /* Check if we still need to grow array */ 2934b23d5de9SAlexander V. Chernikov if (cfg->size >= mi->size) { 2935b23d5de9SAlexander V. Chernikov *pflags = 0; 2936b23d5de9SAlexander V. Chernikov return (0); 2937b23d5de9SAlexander V. Chernikov } 2938b23d5de9SAlexander V. Chernikov 2939b23d5de9SAlexander V. Chernikov memcpy(mi->main_ptr, cfg->main_ptr, cfg->used * sizeof(struct numarray)); 2940b23d5de9SAlexander V. Chernikov 2941b23d5de9SAlexander V. Chernikov return (0); 2942b23d5de9SAlexander V. Chernikov } 2943b23d5de9SAlexander V. Chernikov 2944b23d5de9SAlexander V. Chernikov /* 2945b23d5de9SAlexander V. Chernikov * Switch old & new arrays. 2946b23d5de9SAlexander V. Chernikov */ 2947301290bcSAlexander V. Chernikov static void 2948b23d5de9SAlexander V. Chernikov ta_modify_numarray(void *ta_state, struct table_info *ti, void *ta_buf, 2949b23d5de9SAlexander V. Chernikov uint64_t pflags) 2950b23d5de9SAlexander V. Chernikov { 2951b23d5de9SAlexander V. Chernikov struct mod_item *mi; 2952b23d5de9SAlexander V. Chernikov struct numarray_cfg *cfg; 2953b23d5de9SAlexander V. Chernikov void *old_ptr; 2954b23d5de9SAlexander V. Chernikov 2955b23d5de9SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 2956b23d5de9SAlexander V. Chernikov cfg = (struct numarray_cfg *)ta_state; 2957b23d5de9SAlexander V. Chernikov 2958b23d5de9SAlexander V. Chernikov old_ptr = cfg->main_ptr; 2959b23d5de9SAlexander V. Chernikov cfg->main_ptr = mi->main_ptr; 2960b23d5de9SAlexander V. Chernikov cfg->size = mi->size; 2961b23d5de9SAlexander V. Chernikov ti->state = cfg->main_ptr; 2962b23d5de9SAlexander V. Chernikov 2963b23d5de9SAlexander V. Chernikov mi->main_ptr = old_ptr; 2964b23d5de9SAlexander V. Chernikov } 2965b23d5de9SAlexander V. Chernikov 2966b23d5de9SAlexander V. Chernikov /* 2967b23d5de9SAlexander V. Chernikov * Free unneded array. 2968b23d5de9SAlexander V. Chernikov */ 2969b23d5de9SAlexander V. Chernikov static void 2970b23d5de9SAlexander V. Chernikov ta_flush_mod_numarray(void *ta_buf) 2971b23d5de9SAlexander V. Chernikov { 2972b23d5de9SAlexander V. Chernikov struct mod_item *mi; 2973b23d5de9SAlexander V. Chernikov 2974b23d5de9SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 2975b23d5de9SAlexander V. Chernikov if (mi->main_ptr != NULL) 2976b23d5de9SAlexander V. Chernikov free(mi->main_ptr, M_IPFW); 2977b23d5de9SAlexander V. Chernikov } 2978b23d5de9SAlexander V. Chernikov 2979b23d5de9SAlexander V. Chernikov static int 2980b23d5de9SAlexander V. Chernikov ta_dump_numarray_tentry(void *ta_state, struct table_info *ti, void *e, 2981b23d5de9SAlexander V. Chernikov ipfw_obj_tentry *tent) 2982b23d5de9SAlexander V. Chernikov { 2983b23d5de9SAlexander V. Chernikov struct numarray *na; 2984b23d5de9SAlexander V. Chernikov 2985b23d5de9SAlexander V. Chernikov na = (struct numarray *)e; 2986b23d5de9SAlexander V. Chernikov 2987b23d5de9SAlexander V. Chernikov tent->k.key = na->number; 29880cba2b28SAlexander V. Chernikov tent->v.kidx = na->value; 2989b23d5de9SAlexander V. Chernikov 2990b23d5de9SAlexander V. Chernikov return (0); 2991b23d5de9SAlexander V. Chernikov } 2992b23d5de9SAlexander V. Chernikov 2993b23d5de9SAlexander V. Chernikov static int 2994914bffb6SAlexander V. Chernikov ta_find_numarray_tentry(void *ta_state, struct table_info *ti, 2995914bffb6SAlexander V. Chernikov ipfw_obj_tentry *tent) 2996b23d5de9SAlexander V. Chernikov { 2997b23d5de9SAlexander V. Chernikov struct numarray_cfg *cfg; 2998b23d5de9SAlexander V. Chernikov struct numarray *ri; 2999b23d5de9SAlexander V. Chernikov 3000b23d5de9SAlexander V. Chernikov cfg = (struct numarray_cfg *)ta_state; 3001b23d5de9SAlexander V. Chernikov 3002914bffb6SAlexander V. Chernikov ri = numarray_find(ti, &tent->k.key); 3003b23d5de9SAlexander V. Chernikov 3004b23d5de9SAlexander V. Chernikov if (ri != NULL) { 3005b23d5de9SAlexander V. Chernikov ta_dump_numarray_tentry(ta_state, ti, ri, tent); 3006b23d5de9SAlexander V. Chernikov return (0); 3007b23d5de9SAlexander V. Chernikov } 3008b23d5de9SAlexander V. Chernikov 3009b23d5de9SAlexander V. Chernikov return (ENOENT); 3010b23d5de9SAlexander V. Chernikov } 3011b23d5de9SAlexander V. Chernikov 3012b23d5de9SAlexander V. Chernikov static void 3013b23d5de9SAlexander V. Chernikov ta_foreach_numarray(void *ta_state, struct table_info *ti, ta_foreach_f *f, 3014b23d5de9SAlexander V. Chernikov void *arg) 3015b23d5de9SAlexander V. Chernikov { 3016b23d5de9SAlexander V. Chernikov struct numarray_cfg *cfg; 3017b23d5de9SAlexander V. Chernikov struct numarray *array; 3018b23d5de9SAlexander V. Chernikov int i; 3019b23d5de9SAlexander V. Chernikov 3020b23d5de9SAlexander V. Chernikov cfg = (struct numarray_cfg *)ta_state; 3021b23d5de9SAlexander V. Chernikov array = cfg->main_ptr; 3022b23d5de9SAlexander V. Chernikov 3023b23d5de9SAlexander V. Chernikov for (i = 0; i < cfg->used; i++) 3024b23d5de9SAlexander V. Chernikov f(&array[i], arg); 3025b23d5de9SAlexander V. Chernikov } 3026b23d5de9SAlexander V. Chernikov 3027b23d5de9SAlexander V. Chernikov struct table_algo number_array = { 3028b23d5de9SAlexander V. Chernikov .name = "number:array", 3029b23d5de9SAlexander V. Chernikov .type = IPFW_TABLE_NUMBER, 303057a1cf95SAlexander V. Chernikov .ta_buf_size = sizeof(struct ta_buf_numarray), 3031b23d5de9SAlexander V. Chernikov .init = ta_init_numarray, 3032b23d5de9SAlexander V. Chernikov .destroy = ta_destroy_numarray, 3033b23d5de9SAlexander V. Chernikov .prepare_add = ta_prepare_add_numarray, 3034b23d5de9SAlexander V. Chernikov .prepare_del = ta_prepare_add_numarray, 3035b23d5de9SAlexander V. Chernikov .add = ta_add_numarray, 3036b23d5de9SAlexander V. Chernikov .del = ta_del_numarray, 3037b23d5de9SAlexander V. Chernikov .flush_entry = ta_flush_numarray_entry, 3038b23d5de9SAlexander V. Chernikov .foreach = ta_foreach_numarray, 3039b23d5de9SAlexander V. Chernikov .dump_tentry = ta_dump_numarray_tentry, 3040b23d5de9SAlexander V. Chernikov .find_tentry = ta_find_numarray_tentry, 30415f379342SAlexander V. Chernikov .dump_tinfo = ta_dump_numarray_tinfo, 3042301290bcSAlexander V. Chernikov .need_modify = ta_need_modify_numarray, 3043b23d5de9SAlexander V. Chernikov .prepare_mod = ta_prepare_mod_numarray, 3044b23d5de9SAlexander V. Chernikov .fill_mod = ta_fill_mod_numarray, 3045b23d5de9SAlexander V. Chernikov .modify = ta_modify_numarray, 3046b23d5de9SAlexander V. Chernikov .flush_mod = ta_flush_mod_numarray, 3047b23d5de9SAlexander V. Chernikov }; 3048b23d5de9SAlexander V. Chernikov 3049914bffb6SAlexander V. Chernikov /* 3050914bffb6SAlexander V. Chernikov * flow:hash cmds 3051914bffb6SAlexander V. Chernikov * 3052914bffb6SAlexander V. Chernikov * 3053914bffb6SAlexander V. Chernikov * ti->data: 3054914bffb6SAlexander V. Chernikov * [inv.mask4][inv.mask6][log2hsize4][log2hsize6] 3055914bffb6SAlexander V. Chernikov * [ 8][ 8[ 8][ 8] 3056914bffb6SAlexander V. Chernikov * 3057914bffb6SAlexander V. Chernikov * inv.mask4: 32 - mask 3058914bffb6SAlexander V. Chernikov * inv.mask6: 3059914bffb6SAlexander V. Chernikov * 1) _slow lookup: mask 3060914bffb6SAlexander V. Chernikov * 2) _aligned: (128 - mask) / 8 3061914bffb6SAlexander V. Chernikov * 3) _64: 8 3062914bffb6SAlexander V. Chernikov * 3063914bffb6SAlexander V. Chernikov * 3064914bffb6SAlexander V. Chernikov * pflags: 3065b6ee846eSAlexander V. Chernikov * [hsize4][hsize6] 3066b6ee846eSAlexander V. Chernikov * [ 16][ 16] 3067914bffb6SAlexander V. Chernikov */ 3068914bffb6SAlexander V. Chernikov 3069914bffb6SAlexander V. Chernikov struct fhashentry; 3070914bffb6SAlexander V. Chernikov 3071914bffb6SAlexander V. Chernikov SLIST_HEAD(fhashbhead, fhashentry); 3072914bffb6SAlexander V. Chernikov 3073914bffb6SAlexander V. Chernikov struct fhashentry { 3074914bffb6SAlexander V. Chernikov SLIST_ENTRY(fhashentry) next; 3075914bffb6SAlexander V. Chernikov uint8_t af; 3076914bffb6SAlexander V. Chernikov uint8_t proto; 3077914bffb6SAlexander V. Chernikov uint16_t spare0; 3078914bffb6SAlexander V. Chernikov uint16_t dport; 3079914bffb6SAlexander V. Chernikov uint16_t sport; 3080914bffb6SAlexander V. Chernikov uint32_t value; 3081914bffb6SAlexander V. Chernikov uint32_t spare1; 3082914bffb6SAlexander V. Chernikov }; 3083914bffb6SAlexander V. Chernikov 3084914bffb6SAlexander V. Chernikov struct fhashentry4 { 3085914bffb6SAlexander V. Chernikov struct fhashentry e; 3086914bffb6SAlexander V. Chernikov struct in_addr dip; 3087914bffb6SAlexander V. Chernikov struct in_addr sip; 3088914bffb6SAlexander V. Chernikov }; 3089914bffb6SAlexander V. Chernikov 3090914bffb6SAlexander V. Chernikov struct fhashentry6 { 3091914bffb6SAlexander V. Chernikov struct fhashentry e; 3092914bffb6SAlexander V. Chernikov struct in6_addr dip6; 3093914bffb6SAlexander V. Chernikov struct in6_addr sip6; 3094914bffb6SAlexander V. Chernikov }; 3095914bffb6SAlexander V. Chernikov 3096914bffb6SAlexander V. Chernikov struct fhash_cfg { 3097914bffb6SAlexander V. Chernikov struct fhashbhead *head; 3098914bffb6SAlexander V. Chernikov size_t size; 3099914bffb6SAlexander V. Chernikov size_t items; 3100914bffb6SAlexander V. Chernikov struct fhashentry4 fe4; 3101914bffb6SAlexander V. Chernikov struct fhashentry6 fe6; 3102914bffb6SAlexander V. Chernikov }; 3103914bffb6SAlexander V. Chernikov 31043fe2ef91SAlexander V. Chernikov struct ta_buf_fhash { 31050bce0c23SAlexander V. Chernikov void *ent_ptr; 31060bce0c23SAlexander V. Chernikov struct fhashentry6 fe6; 31070bce0c23SAlexander V. Chernikov }; 31080bce0c23SAlexander V. Chernikov 31099fe15d06SAlexander V. Chernikov static __inline int cmp_flow_ent(struct fhashentry *a, 31109fe15d06SAlexander V. Chernikov struct fhashentry *b, size_t sz); 31119fe15d06SAlexander V. Chernikov static __inline uint32_t hash_flow4(struct fhashentry4 *f, int hsize); 31129fe15d06SAlexander V. Chernikov static __inline uint32_t hash_flow6(struct fhashentry6 *f, int hsize); 31139fe15d06SAlexander V. Chernikov static uint32_t hash_flow_ent(struct fhashentry *ent, uint32_t size); 31149fe15d06SAlexander V. Chernikov static int ta_lookup_fhash(struct table_info *ti, void *key, uint32_t keylen, 31159fe15d06SAlexander V. Chernikov uint32_t *val); 31169fe15d06SAlexander V. Chernikov static int ta_init_fhash(struct ip_fw_chain *ch, void **ta_state, 31179fe15d06SAlexander V. Chernikov struct table_info *ti, char *data, uint8_t tflags); 31189fe15d06SAlexander V. Chernikov static void ta_destroy_fhash(void *ta_state, struct table_info *ti); 31199fe15d06SAlexander V. Chernikov static void ta_dump_fhash_tinfo(void *ta_state, struct table_info *ti, 31209fe15d06SAlexander V. Chernikov ipfw_ta_tinfo *tinfo); 31219fe15d06SAlexander V. Chernikov static int ta_dump_fhash_tentry(void *ta_state, struct table_info *ti, 31229fe15d06SAlexander V. Chernikov void *e, ipfw_obj_tentry *tent); 31239fe15d06SAlexander V. Chernikov static int tei_to_fhash_ent(struct tentry_info *tei, struct fhashentry *ent); 31249fe15d06SAlexander V. Chernikov static int ta_find_fhash_tentry(void *ta_state, struct table_info *ti, 31259fe15d06SAlexander V. Chernikov ipfw_obj_tentry *tent); 31269fe15d06SAlexander V. Chernikov static void ta_foreach_fhash(void *ta_state, struct table_info *ti, 31279fe15d06SAlexander V. Chernikov ta_foreach_f *f, void *arg); 31289fe15d06SAlexander V. Chernikov static int ta_prepare_add_fhash(struct ip_fw_chain *ch, 31299fe15d06SAlexander V. Chernikov struct tentry_info *tei, void *ta_buf); 31309fe15d06SAlexander V. Chernikov static int ta_add_fhash(void *ta_state, struct table_info *ti, 31319fe15d06SAlexander V. Chernikov struct tentry_info *tei, void *ta_buf, uint32_t *pnum); 31329fe15d06SAlexander V. Chernikov static int ta_prepare_del_fhash(struct ip_fw_chain *ch, struct tentry_info *tei, 31339fe15d06SAlexander V. Chernikov void *ta_buf); 31349fe15d06SAlexander V. Chernikov static int ta_del_fhash(void *ta_state, struct table_info *ti, 31359fe15d06SAlexander V. Chernikov struct tentry_info *tei, void *ta_buf, uint32_t *pnum); 31369fe15d06SAlexander V. Chernikov static void ta_flush_fhash_entry(struct ip_fw_chain *ch, struct tentry_info *tei, 31379fe15d06SAlexander V. Chernikov void *ta_buf); 31389fe15d06SAlexander V. Chernikov static int ta_need_modify_fhash(void *ta_state, struct table_info *ti, 31399fe15d06SAlexander V. Chernikov uint32_t count, uint64_t *pflags); 31409fe15d06SAlexander V. Chernikov static int ta_prepare_mod_fhash(void *ta_buf, uint64_t *pflags); 31419fe15d06SAlexander V. Chernikov static int ta_fill_mod_fhash(void *ta_state, struct table_info *ti, 31429fe15d06SAlexander V. Chernikov void *ta_buf, uint64_t *pflags); 31439fe15d06SAlexander V. Chernikov static void ta_modify_fhash(void *ta_state, struct table_info *ti, void *ta_buf, 31449fe15d06SAlexander V. Chernikov uint64_t pflags); 31459fe15d06SAlexander V. Chernikov static void ta_flush_mod_fhash(void *ta_buf); 31469fe15d06SAlexander V. Chernikov 3147914bffb6SAlexander V. Chernikov static __inline int 3148914bffb6SAlexander V. Chernikov cmp_flow_ent(struct fhashentry *a, struct fhashentry *b, size_t sz) 3149914bffb6SAlexander V. Chernikov { 3150914bffb6SAlexander V. Chernikov uint64_t *ka, *kb; 3151914bffb6SAlexander V. Chernikov 3152914bffb6SAlexander V. Chernikov ka = (uint64_t *)(&a->next + 1); 3153914bffb6SAlexander V. Chernikov kb = (uint64_t *)(&b->next + 1); 3154914bffb6SAlexander V. Chernikov 3155914bffb6SAlexander V. Chernikov if (*ka == *kb && (memcmp(a + 1, b + 1, sz) == 0)) 3156914bffb6SAlexander V. Chernikov return (1); 3157914bffb6SAlexander V. Chernikov 3158914bffb6SAlexander V. Chernikov return (0); 3159914bffb6SAlexander V. Chernikov } 3160914bffb6SAlexander V. Chernikov 3161914bffb6SAlexander V. Chernikov static __inline uint32_t 3162914bffb6SAlexander V. Chernikov hash_flow4(struct fhashentry4 *f, int hsize) 3163914bffb6SAlexander V. Chernikov { 3164914bffb6SAlexander V. Chernikov uint32_t i; 3165914bffb6SAlexander V. Chernikov 3166914bffb6SAlexander V. Chernikov i = (f->dip.s_addr) ^ (f->sip.s_addr) ^ (f->e.dport) ^ (f->e.sport); 3167914bffb6SAlexander V. Chernikov 3168914bffb6SAlexander V. Chernikov return (i % (hsize - 1)); 3169914bffb6SAlexander V. Chernikov } 3170914bffb6SAlexander V. Chernikov 3171914bffb6SAlexander V. Chernikov static __inline uint32_t 3172914bffb6SAlexander V. Chernikov hash_flow6(struct fhashentry6 *f, int hsize) 3173914bffb6SAlexander V. Chernikov { 3174914bffb6SAlexander V. Chernikov uint32_t i; 3175914bffb6SAlexander V. Chernikov 3176914bffb6SAlexander V. Chernikov i = (f->dip6.__u6_addr.__u6_addr32[2]) ^ 3177914bffb6SAlexander V. Chernikov (f->dip6.__u6_addr.__u6_addr32[3]) ^ 3178914bffb6SAlexander V. Chernikov (f->sip6.__u6_addr.__u6_addr32[2]) ^ 3179914bffb6SAlexander V. Chernikov (f->sip6.__u6_addr.__u6_addr32[3]) ^ 3180914bffb6SAlexander V. Chernikov (f->e.dport) ^ (f->e.sport); 3181914bffb6SAlexander V. Chernikov 3182914bffb6SAlexander V. Chernikov return (i % (hsize - 1)); 3183914bffb6SAlexander V. Chernikov } 3184914bffb6SAlexander V. Chernikov 3185914bffb6SAlexander V. Chernikov static uint32_t 3186914bffb6SAlexander V. Chernikov hash_flow_ent(struct fhashentry *ent, uint32_t size) 3187914bffb6SAlexander V. Chernikov { 3188914bffb6SAlexander V. Chernikov uint32_t hash; 3189914bffb6SAlexander V. Chernikov 3190914bffb6SAlexander V. Chernikov if (ent->af == AF_INET) { 3191914bffb6SAlexander V. Chernikov hash = hash_flow4((struct fhashentry4 *)ent, size); 3192914bffb6SAlexander V. Chernikov } else { 3193914bffb6SAlexander V. Chernikov hash = hash_flow6((struct fhashentry6 *)ent, size); 3194914bffb6SAlexander V. Chernikov } 3195914bffb6SAlexander V. Chernikov 3196914bffb6SAlexander V. Chernikov return (hash); 3197914bffb6SAlexander V. Chernikov } 3198914bffb6SAlexander V. Chernikov 3199914bffb6SAlexander V. Chernikov static int 3200914bffb6SAlexander V. Chernikov ta_lookup_fhash(struct table_info *ti, void *key, uint32_t keylen, 3201914bffb6SAlexander V. Chernikov uint32_t *val) 3202914bffb6SAlexander V. Chernikov { 3203914bffb6SAlexander V. Chernikov struct fhashbhead *head; 3204914bffb6SAlexander V. Chernikov struct fhashentry *ent; 3205914bffb6SAlexander V. Chernikov struct fhashentry4 *m4; 3206914bffb6SAlexander V. Chernikov struct ipfw_flow_id *id; 3207914bffb6SAlexander V. Chernikov uint16_t hash, hsize; 3208914bffb6SAlexander V. Chernikov 3209914bffb6SAlexander V. Chernikov id = (struct ipfw_flow_id *)key; 3210914bffb6SAlexander V. Chernikov head = (struct fhashbhead *)ti->state; 3211914bffb6SAlexander V. Chernikov hsize = ti->data; 3212914bffb6SAlexander V. Chernikov m4 = (struct fhashentry4 *)ti->xstate; 3213914bffb6SAlexander V. Chernikov 3214914bffb6SAlexander V. Chernikov if (id->addr_type == 4) { 3215914bffb6SAlexander V. Chernikov struct fhashentry4 f; 3216914bffb6SAlexander V. Chernikov 3217914bffb6SAlexander V. Chernikov /* Copy hash mask */ 3218914bffb6SAlexander V. Chernikov f = *m4; 3219914bffb6SAlexander V. Chernikov 3220914bffb6SAlexander V. Chernikov f.dip.s_addr &= id->dst_ip; 3221914bffb6SAlexander V. Chernikov f.sip.s_addr &= id->src_ip; 3222914bffb6SAlexander V. Chernikov f.e.dport &= id->dst_port; 3223914bffb6SAlexander V. Chernikov f.e.sport &= id->src_port; 3224914bffb6SAlexander V. Chernikov f.e.proto &= id->proto; 3225914bffb6SAlexander V. Chernikov hash = hash_flow4(&f, hsize); 3226914bffb6SAlexander V. Chernikov SLIST_FOREACH(ent, &head[hash], next) { 3227914bffb6SAlexander V. Chernikov if (cmp_flow_ent(ent, &f.e, 2 * 4) != 0) { 3228914bffb6SAlexander V. Chernikov *val = ent->value; 3229914bffb6SAlexander V. Chernikov return (1); 3230914bffb6SAlexander V. Chernikov } 3231914bffb6SAlexander V. Chernikov } 3232914bffb6SAlexander V. Chernikov } else if (id->addr_type == 6) { 3233914bffb6SAlexander V. Chernikov struct fhashentry6 f; 3234914bffb6SAlexander V. Chernikov uint64_t *fp, *idp; 3235914bffb6SAlexander V. Chernikov 3236914bffb6SAlexander V. Chernikov /* Copy hash mask */ 3237914bffb6SAlexander V. Chernikov f = *((struct fhashentry6 *)(m4 + 1)); 3238914bffb6SAlexander V. Chernikov 3239914bffb6SAlexander V. Chernikov /* Handle lack of __u6_addr.__u6_addr64 */ 3240914bffb6SAlexander V. Chernikov fp = (uint64_t *)&f.dip6; 3241914bffb6SAlexander V. Chernikov idp = (uint64_t *)&id->dst_ip6; 3242914bffb6SAlexander V. Chernikov /* src IPv6 is stored after dst IPv6 */ 3243914bffb6SAlexander V. Chernikov *fp++ &= *idp++; 3244914bffb6SAlexander V. Chernikov *fp++ &= *idp++; 3245914bffb6SAlexander V. Chernikov *fp++ &= *idp++; 3246914bffb6SAlexander V. Chernikov *fp &= *idp; 3247914bffb6SAlexander V. Chernikov f.e.dport &= id->dst_port; 3248914bffb6SAlexander V. Chernikov f.e.sport &= id->src_port; 3249914bffb6SAlexander V. Chernikov f.e.proto &= id->proto; 3250914bffb6SAlexander V. Chernikov hash = hash_flow6(&f, hsize); 3251914bffb6SAlexander V. Chernikov SLIST_FOREACH(ent, &head[hash], next) { 3252914bffb6SAlexander V. Chernikov if (cmp_flow_ent(ent, &f.e, 2 * 16) != 0) { 3253914bffb6SAlexander V. Chernikov *val = ent->value; 3254914bffb6SAlexander V. Chernikov return (1); 3255914bffb6SAlexander V. Chernikov } 3256914bffb6SAlexander V. Chernikov } 3257914bffb6SAlexander V. Chernikov } 3258914bffb6SAlexander V. Chernikov 3259914bffb6SAlexander V. Chernikov return (0); 3260914bffb6SAlexander V. Chernikov } 3261914bffb6SAlexander V. Chernikov 3262914bffb6SAlexander V. Chernikov /* 3263914bffb6SAlexander V. Chernikov * New table. 3264914bffb6SAlexander V. Chernikov */ 3265914bffb6SAlexander V. Chernikov static int 3266914bffb6SAlexander V. Chernikov ta_init_fhash(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti, 3267914bffb6SAlexander V. Chernikov char *data, uint8_t tflags) 3268914bffb6SAlexander V. Chernikov { 3269914bffb6SAlexander V. Chernikov struct fhash_cfg *cfg; 3270914bffb6SAlexander V. Chernikov struct fhashentry4 *fe4; 3271914bffb6SAlexander V. Chernikov struct fhashentry6 *fe6; 3272*d821d364SPedro F. Giffuni u_int i; 3273914bffb6SAlexander V. Chernikov 3274914bffb6SAlexander V. Chernikov cfg = malloc(sizeof(struct fhash_cfg), M_IPFW, M_WAITOK | M_ZERO); 3275914bffb6SAlexander V. Chernikov 3276914bffb6SAlexander V. Chernikov cfg->size = 512; 3277914bffb6SAlexander V. Chernikov 3278914bffb6SAlexander V. Chernikov cfg->head = malloc(sizeof(struct fhashbhead) * cfg->size, M_IPFW, 3279914bffb6SAlexander V. Chernikov M_WAITOK | M_ZERO); 3280914bffb6SAlexander V. Chernikov for (i = 0; i < cfg->size; i++) 3281914bffb6SAlexander V. Chernikov SLIST_INIT(&cfg->head[i]); 3282914bffb6SAlexander V. Chernikov 3283914bffb6SAlexander V. Chernikov /* Fill in fe masks based on @tflags */ 3284914bffb6SAlexander V. Chernikov fe4 = &cfg->fe4; 3285914bffb6SAlexander V. Chernikov fe6 = &cfg->fe6; 3286914bffb6SAlexander V. Chernikov if (tflags & IPFW_TFFLAG_SRCIP) { 3287914bffb6SAlexander V. Chernikov memset(&fe4->sip, 0xFF, sizeof(fe4->sip)); 3288914bffb6SAlexander V. Chernikov memset(&fe6->sip6, 0xFF, sizeof(fe6->sip6)); 3289914bffb6SAlexander V. Chernikov } 3290914bffb6SAlexander V. Chernikov if (tflags & IPFW_TFFLAG_DSTIP) { 3291914bffb6SAlexander V. Chernikov memset(&fe4->dip, 0xFF, sizeof(fe4->dip)); 3292914bffb6SAlexander V. Chernikov memset(&fe6->dip6, 0xFF, sizeof(fe6->dip6)); 3293914bffb6SAlexander V. Chernikov } 3294914bffb6SAlexander V. Chernikov if (tflags & IPFW_TFFLAG_SRCPORT) { 3295914bffb6SAlexander V. Chernikov memset(&fe4->e.sport, 0xFF, sizeof(fe4->e.sport)); 3296914bffb6SAlexander V. Chernikov memset(&fe6->e.sport, 0xFF, sizeof(fe6->e.sport)); 3297914bffb6SAlexander V. Chernikov } 3298914bffb6SAlexander V. Chernikov if (tflags & IPFW_TFFLAG_DSTPORT) { 3299914bffb6SAlexander V. Chernikov memset(&fe4->e.dport, 0xFF, sizeof(fe4->e.dport)); 3300914bffb6SAlexander V. Chernikov memset(&fe6->e.dport, 0xFF, sizeof(fe6->e.dport)); 3301914bffb6SAlexander V. Chernikov } 3302914bffb6SAlexander V. Chernikov if (tflags & IPFW_TFFLAG_PROTO) { 3303914bffb6SAlexander V. Chernikov memset(&fe4->e.proto, 0xFF, sizeof(fe4->e.proto)); 3304914bffb6SAlexander V. Chernikov memset(&fe6->e.proto, 0xFF, sizeof(fe6->e.proto)); 3305914bffb6SAlexander V. Chernikov } 3306914bffb6SAlexander V. Chernikov 3307914bffb6SAlexander V. Chernikov fe4->e.af = AF_INET; 3308914bffb6SAlexander V. Chernikov fe6->e.af = AF_INET6; 3309914bffb6SAlexander V. Chernikov 3310914bffb6SAlexander V. Chernikov *ta_state = cfg; 3311914bffb6SAlexander V. Chernikov ti->state = cfg->head; 3312914bffb6SAlexander V. Chernikov ti->xstate = &cfg->fe4; 3313914bffb6SAlexander V. Chernikov ti->data = cfg->size; 3314914bffb6SAlexander V. Chernikov ti->lookup = ta_lookup_fhash; 3315914bffb6SAlexander V. Chernikov 3316914bffb6SAlexander V. Chernikov return (0); 3317914bffb6SAlexander V. Chernikov } 3318914bffb6SAlexander V. Chernikov 3319914bffb6SAlexander V. Chernikov static void 3320914bffb6SAlexander V. Chernikov ta_destroy_fhash(void *ta_state, struct table_info *ti) 3321914bffb6SAlexander V. Chernikov { 3322914bffb6SAlexander V. Chernikov struct fhash_cfg *cfg; 3323914bffb6SAlexander V. Chernikov struct fhashentry *ent, *ent_next; 3324914bffb6SAlexander V. Chernikov int i; 3325914bffb6SAlexander V. Chernikov 3326914bffb6SAlexander V. Chernikov cfg = (struct fhash_cfg *)ta_state; 3327914bffb6SAlexander V. Chernikov 3328914bffb6SAlexander V. Chernikov for (i = 0; i < cfg->size; i++) 3329914bffb6SAlexander V. Chernikov SLIST_FOREACH_SAFE(ent, &cfg->head[i], next, ent_next) 3330914bffb6SAlexander V. Chernikov free(ent, M_IPFW_TBL); 3331914bffb6SAlexander V. Chernikov 3332914bffb6SAlexander V. Chernikov free(cfg->head, M_IPFW); 3333914bffb6SAlexander V. Chernikov free(cfg, M_IPFW); 3334914bffb6SAlexander V. Chernikov } 3335914bffb6SAlexander V. Chernikov 33365f379342SAlexander V. Chernikov /* 33375f379342SAlexander V. Chernikov * Provide algo-specific table info 33385f379342SAlexander V. Chernikov */ 33395f379342SAlexander V. Chernikov static void 33405f379342SAlexander V. Chernikov ta_dump_fhash_tinfo(void *ta_state, struct table_info *ti, ipfw_ta_tinfo *tinfo) 33415f379342SAlexander V. Chernikov { 33425f379342SAlexander V. Chernikov struct fhash_cfg *cfg; 33435f379342SAlexander V. Chernikov 33445f379342SAlexander V. Chernikov cfg = (struct fhash_cfg *)ta_state; 33455f379342SAlexander V. Chernikov 33465f379342SAlexander V. Chernikov tinfo->flags = IPFW_TATFLAGS_AFITEM; 33475f379342SAlexander V. Chernikov tinfo->taclass4 = IPFW_TACLASS_HASH; 33485f379342SAlexander V. Chernikov tinfo->size4 = cfg->size; 33495f379342SAlexander V. Chernikov tinfo->count4 = cfg->items; 33505f379342SAlexander V. Chernikov tinfo->itemsize4 = sizeof(struct fhashentry4); 33515f379342SAlexander V. Chernikov tinfo->itemsize6 = sizeof(struct fhashentry6); 33525f379342SAlexander V. Chernikov } 33535f379342SAlexander V. Chernikov 3354914bffb6SAlexander V. Chernikov static int 3355914bffb6SAlexander V. Chernikov ta_dump_fhash_tentry(void *ta_state, struct table_info *ti, void *e, 3356914bffb6SAlexander V. Chernikov ipfw_obj_tentry *tent) 3357914bffb6SAlexander V. Chernikov { 3358914bffb6SAlexander V. Chernikov struct fhash_cfg *cfg; 3359914bffb6SAlexander V. Chernikov struct fhashentry *ent; 3360914bffb6SAlexander V. Chernikov struct fhashentry4 *fe4; 33619fe15d06SAlexander V. Chernikov #ifdef INET6 3362914bffb6SAlexander V. Chernikov struct fhashentry6 *fe6; 33639fe15d06SAlexander V. Chernikov #endif 3364914bffb6SAlexander V. Chernikov struct tflow_entry *tfe; 3365914bffb6SAlexander V. Chernikov 3366914bffb6SAlexander V. Chernikov cfg = (struct fhash_cfg *)ta_state; 3367914bffb6SAlexander V. Chernikov ent = (struct fhashentry *)e; 3368914bffb6SAlexander V. Chernikov tfe = &tent->k.flow; 3369914bffb6SAlexander V. Chernikov 3370914bffb6SAlexander V. Chernikov tfe->af = ent->af; 3371914bffb6SAlexander V. Chernikov tfe->proto = ent->proto; 3372914bffb6SAlexander V. Chernikov tfe->dport = htons(ent->dport); 3373914bffb6SAlexander V. Chernikov tfe->sport = htons(ent->sport); 33740cba2b28SAlexander V. Chernikov tent->v.kidx = ent->value; 3375914bffb6SAlexander V. Chernikov tent->subtype = ent->af; 3376914bffb6SAlexander V. Chernikov 3377914bffb6SAlexander V. Chernikov if (ent->af == AF_INET) { 3378914bffb6SAlexander V. Chernikov fe4 = (struct fhashentry4 *)ent; 3379914bffb6SAlexander V. Chernikov tfe->a.a4.sip.s_addr = htonl(fe4->sip.s_addr); 3380914bffb6SAlexander V. Chernikov tfe->a.a4.dip.s_addr = htonl(fe4->dip.s_addr); 3381914bffb6SAlexander V. Chernikov tent->masklen = 32; 3382914bffb6SAlexander V. Chernikov #ifdef INET6 3383914bffb6SAlexander V. Chernikov } else { 3384914bffb6SAlexander V. Chernikov fe6 = (struct fhashentry6 *)ent; 3385914bffb6SAlexander V. Chernikov tfe->a.a6.sip6 = fe6->sip6; 3386914bffb6SAlexander V. Chernikov tfe->a.a6.dip6 = fe6->dip6; 3387914bffb6SAlexander V. Chernikov tent->masklen = 128; 3388914bffb6SAlexander V. Chernikov #endif 3389914bffb6SAlexander V. Chernikov } 3390914bffb6SAlexander V. Chernikov 3391914bffb6SAlexander V. Chernikov return (0); 3392914bffb6SAlexander V. Chernikov } 3393914bffb6SAlexander V. Chernikov 3394914bffb6SAlexander V. Chernikov static int 3395914bffb6SAlexander V. Chernikov tei_to_fhash_ent(struct tentry_info *tei, struct fhashentry *ent) 3396914bffb6SAlexander V. Chernikov { 3397d699ee2dSAlexander V. Chernikov #ifdef INET 3398914bffb6SAlexander V. Chernikov struct fhashentry4 *fe4; 3399d699ee2dSAlexander V. Chernikov #endif 3400d699ee2dSAlexander V. Chernikov #ifdef INET6 3401914bffb6SAlexander V. Chernikov struct fhashentry6 *fe6; 3402d699ee2dSAlexander V. Chernikov #endif 3403914bffb6SAlexander V. Chernikov struct tflow_entry *tfe; 3404914bffb6SAlexander V. Chernikov 3405914bffb6SAlexander V. Chernikov tfe = (struct tflow_entry *)tei->paddr; 3406914bffb6SAlexander V. Chernikov 3407914bffb6SAlexander V. Chernikov ent->af = tei->subtype; 3408914bffb6SAlexander V. Chernikov ent->proto = tfe->proto; 3409914bffb6SAlexander V. Chernikov ent->dport = ntohs(tfe->dport); 3410914bffb6SAlexander V. Chernikov ent->sport = ntohs(tfe->sport); 3411914bffb6SAlexander V. Chernikov 3412914bffb6SAlexander V. Chernikov if (tei->subtype == AF_INET) { 3413914bffb6SAlexander V. Chernikov #ifdef INET 3414914bffb6SAlexander V. Chernikov fe4 = (struct fhashentry4 *)ent; 3415914bffb6SAlexander V. Chernikov fe4->sip.s_addr = ntohl(tfe->a.a4.sip.s_addr); 3416914bffb6SAlexander V. Chernikov fe4->dip.s_addr = ntohl(tfe->a.a4.dip.s_addr); 3417914bffb6SAlexander V. Chernikov #endif 3418914bffb6SAlexander V. Chernikov #ifdef INET6 3419914bffb6SAlexander V. Chernikov } else if (tei->subtype == AF_INET6) { 3420914bffb6SAlexander V. Chernikov fe6 = (struct fhashentry6 *)ent; 3421914bffb6SAlexander V. Chernikov fe6->sip6 = tfe->a.a6.sip6; 3422914bffb6SAlexander V. Chernikov fe6->dip6 = tfe->a.a6.dip6; 3423914bffb6SAlexander V. Chernikov #endif 3424914bffb6SAlexander V. Chernikov } else { 3425914bffb6SAlexander V. Chernikov /* Unknown CIDR type */ 3426914bffb6SAlexander V. Chernikov return (EINVAL); 3427914bffb6SAlexander V. Chernikov } 3428914bffb6SAlexander V. Chernikov 3429914bffb6SAlexander V. Chernikov return (0); 3430914bffb6SAlexander V. Chernikov } 3431914bffb6SAlexander V. Chernikov 3432914bffb6SAlexander V. Chernikov 3433914bffb6SAlexander V. Chernikov static int 3434914bffb6SAlexander V. Chernikov ta_find_fhash_tentry(void *ta_state, struct table_info *ti, 3435914bffb6SAlexander V. Chernikov ipfw_obj_tentry *tent) 3436914bffb6SAlexander V. Chernikov { 3437914bffb6SAlexander V. Chernikov struct fhash_cfg *cfg; 3438914bffb6SAlexander V. Chernikov struct fhashbhead *head; 3439914bffb6SAlexander V. Chernikov struct fhashentry *ent, *tmp; 3440914bffb6SAlexander V. Chernikov struct fhashentry6 fe6; 3441914bffb6SAlexander V. Chernikov struct tentry_info tei; 3442914bffb6SAlexander V. Chernikov int error; 3443914bffb6SAlexander V. Chernikov uint32_t hash; 3444914bffb6SAlexander V. Chernikov size_t sz; 3445914bffb6SAlexander V. Chernikov 3446914bffb6SAlexander V. Chernikov cfg = (struct fhash_cfg *)ta_state; 3447914bffb6SAlexander V. Chernikov 3448914bffb6SAlexander V. Chernikov ent = &fe6.e; 3449914bffb6SAlexander V. Chernikov 3450914bffb6SAlexander V. Chernikov memset(&fe6, 0, sizeof(fe6)); 3451914bffb6SAlexander V. Chernikov memset(&tei, 0, sizeof(tei)); 3452914bffb6SAlexander V. Chernikov 3453914bffb6SAlexander V. Chernikov tei.paddr = &tent->k.flow; 3454914bffb6SAlexander V. Chernikov tei.subtype = tent->subtype; 3455914bffb6SAlexander V. Chernikov 3456914bffb6SAlexander V. Chernikov if ((error = tei_to_fhash_ent(&tei, ent)) != 0) 3457914bffb6SAlexander V. Chernikov return (error); 3458914bffb6SAlexander V. Chernikov 3459914bffb6SAlexander V. Chernikov head = cfg->head; 3460914bffb6SAlexander V. Chernikov hash = hash_flow_ent(ent, cfg->size); 3461914bffb6SAlexander V. Chernikov 3462914bffb6SAlexander V. Chernikov if (tei.subtype == AF_INET) 3463914bffb6SAlexander V. Chernikov sz = 2 * sizeof(struct in_addr); 3464914bffb6SAlexander V. Chernikov else 3465914bffb6SAlexander V. Chernikov sz = 2 * sizeof(struct in6_addr); 3466914bffb6SAlexander V. Chernikov 3467914bffb6SAlexander V. Chernikov /* Check for existence */ 3468914bffb6SAlexander V. Chernikov SLIST_FOREACH(tmp, &head[hash], next) { 3469914bffb6SAlexander V. Chernikov if (cmp_flow_ent(tmp, ent, sz) != 0) { 3470914bffb6SAlexander V. Chernikov ta_dump_fhash_tentry(ta_state, ti, tmp, tent); 3471914bffb6SAlexander V. Chernikov return (0); 3472914bffb6SAlexander V. Chernikov } 3473914bffb6SAlexander V. Chernikov } 3474914bffb6SAlexander V. Chernikov 3475914bffb6SAlexander V. Chernikov return (ENOENT); 3476914bffb6SAlexander V. Chernikov } 3477914bffb6SAlexander V. Chernikov 3478914bffb6SAlexander V. Chernikov static void 3479914bffb6SAlexander V. Chernikov ta_foreach_fhash(void *ta_state, struct table_info *ti, ta_foreach_f *f, 3480914bffb6SAlexander V. Chernikov void *arg) 3481914bffb6SAlexander V. Chernikov { 3482914bffb6SAlexander V. Chernikov struct fhash_cfg *cfg; 3483914bffb6SAlexander V. Chernikov struct fhashentry *ent, *ent_next; 3484914bffb6SAlexander V. Chernikov int i; 3485914bffb6SAlexander V. Chernikov 3486914bffb6SAlexander V. Chernikov cfg = (struct fhash_cfg *)ta_state; 3487914bffb6SAlexander V. Chernikov 3488914bffb6SAlexander V. Chernikov for (i = 0; i < cfg->size; i++) 3489914bffb6SAlexander V. Chernikov SLIST_FOREACH_SAFE(ent, &cfg->head[i], next, ent_next) 3490914bffb6SAlexander V. Chernikov f(ent, arg); 3491914bffb6SAlexander V. Chernikov } 3492914bffb6SAlexander V. Chernikov 3493914bffb6SAlexander V. Chernikov static int 3494914bffb6SAlexander V. Chernikov ta_prepare_add_fhash(struct ip_fw_chain *ch, struct tentry_info *tei, 3495914bffb6SAlexander V. Chernikov void *ta_buf) 3496914bffb6SAlexander V. Chernikov { 3497914bffb6SAlexander V. Chernikov struct ta_buf_fhash *tb; 3498914bffb6SAlexander V. Chernikov struct fhashentry *ent; 3499914bffb6SAlexander V. Chernikov size_t sz; 3500914bffb6SAlexander V. Chernikov int error; 3501914bffb6SAlexander V. Chernikov 3502914bffb6SAlexander V. Chernikov tb = (struct ta_buf_fhash *)ta_buf; 3503914bffb6SAlexander V. Chernikov 3504914bffb6SAlexander V. Chernikov if (tei->subtype == AF_INET) 3505914bffb6SAlexander V. Chernikov sz = sizeof(struct fhashentry4); 3506914bffb6SAlexander V. Chernikov else if (tei->subtype == AF_INET6) 3507914bffb6SAlexander V. Chernikov sz = sizeof(struct fhashentry6); 3508914bffb6SAlexander V. Chernikov else 3509914bffb6SAlexander V. Chernikov return (EINVAL); 3510914bffb6SAlexander V. Chernikov 3511914bffb6SAlexander V. Chernikov ent = malloc(sz, M_IPFW_TBL, M_WAITOK | M_ZERO); 3512914bffb6SAlexander V. Chernikov 3513914bffb6SAlexander V. Chernikov error = tei_to_fhash_ent(tei, ent); 3514914bffb6SAlexander V. Chernikov if (error != 0) { 3515914bffb6SAlexander V. Chernikov free(ent, M_IPFW_TBL); 3516914bffb6SAlexander V. Chernikov return (error); 3517914bffb6SAlexander V. Chernikov } 3518914bffb6SAlexander V. Chernikov tb->ent_ptr = ent; 3519914bffb6SAlexander V. Chernikov 3520914bffb6SAlexander V. Chernikov return (0); 3521914bffb6SAlexander V. Chernikov } 3522914bffb6SAlexander V. Chernikov 3523914bffb6SAlexander V. Chernikov static int 3524914bffb6SAlexander V. Chernikov ta_add_fhash(void *ta_state, struct table_info *ti, struct tentry_info *tei, 3525b6ee846eSAlexander V. Chernikov void *ta_buf, uint32_t *pnum) 3526914bffb6SAlexander V. Chernikov { 3527914bffb6SAlexander V. Chernikov struct fhash_cfg *cfg; 3528914bffb6SAlexander V. Chernikov struct fhashbhead *head; 3529914bffb6SAlexander V. Chernikov struct fhashentry *ent, *tmp; 3530914bffb6SAlexander V. Chernikov struct ta_buf_fhash *tb; 3531914bffb6SAlexander V. Chernikov int exists; 3532648e8380SAlexander V. Chernikov uint32_t hash, value; 3533914bffb6SAlexander V. Chernikov size_t sz; 3534914bffb6SAlexander V. Chernikov 3535914bffb6SAlexander V. Chernikov cfg = (struct fhash_cfg *)ta_state; 3536914bffb6SAlexander V. Chernikov tb = (struct ta_buf_fhash *)ta_buf; 3537914bffb6SAlexander V. Chernikov ent = (struct fhashentry *)tb->ent_ptr; 3538914bffb6SAlexander V. Chernikov exists = 0; 3539914bffb6SAlexander V. Chernikov 354013263632SAlexander V. Chernikov /* Read current value from @tei */ 354113263632SAlexander V. Chernikov ent->value = tei->value; 354213263632SAlexander V. Chernikov 3543914bffb6SAlexander V. Chernikov head = cfg->head; 3544914bffb6SAlexander V. Chernikov hash = hash_flow_ent(ent, cfg->size); 3545914bffb6SAlexander V. Chernikov 3546914bffb6SAlexander V. Chernikov if (tei->subtype == AF_INET) 3547914bffb6SAlexander V. Chernikov sz = 2 * sizeof(struct in_addr); 3548914bffb6SAlexander V. Chernikov else 3549914bffb6SAlexander V. Chernikov sz = 2 * sizeof(struct in6_addr); 3550914bffb6SAlexander V. Chernikov 3551914bffb6SAlexander V. Chernikov /* Check for existence */ 3552914bffb6SAlexander V. Chernikov SLIST_FOREACH(tmp, &head[hash], next) { 3553914bffb6SAlexander V. Chernikov if (cmp_flow_ent(tmp, ent, sz) != 0) { 3554914bffb6SAlexander V. Chernikov exists = 1; 3555914bffb6SAlexander V. Chernikov break; 3556914bffb6SAlexander V. Chernikov } 3557914bffb6SAlexander V. Chernikov } 3558914bffb6SAlexander V. Chernikov 3559914bffb6SAlexander V. Chernikov if (exists == 1) { 3560914bffb6SAlexander V. Chernikov if ((tei->flags & TEI_FLAGS_UPDATE) == 0) 3561914bffb6SAlexander V. Chernikov return (EEXIST); 3562914bffb6SAlexander V. Chernikov /* Record already exists. Update value if we're asked to */ 3563648e8380SAlexander V. Chernikov /* Exchange values between tmp and @tei */ 3564648e8380SAlexander V. Chernikov value = tmp->value; 3565914bffb6SAlexander V. Chernikov tmp->value = tei->value; 3566648e8380SAlexander V. Chernikov tei->value = value; 3567914bffb6SAlexander V. Chernikov /* Indicate that update has happened instead of addition */ 3568914bffb6SAlexander V. Chernikov tei->flags |= TEI_FLAGS_UPDATED; 3569914bffb6SAlexander V. Chernikov *pnum = 0; 3570914bffb6SAlexander V. Chernikov } else { 35714c0c07a5SAlexander V. Chernikov if ((tei->flags & TEI_FLAGS_DONTADD) != 0) 35724c0c07a5SAlexander V. Chernikov return (EFBIG); 35734c0c07a5SAlexander V. Chernikov 3574914bffb6SAlexander V. Chernikov SLIST_INSERT_HEAD(&head[hash], ent, next); 3575914bffb6SAlexander V. Chernikov tb->ent_ptr = NULL; 3576914bffb6SAlexander V. Chernikov *pnum = 1; 3577914bffb6SAlexander V. Chernikov 3578914bffb6SAlexander V. Chernikov /* Update counters and check if we need to grow hash */ 3579914bffb6SAlexander V. Chernikov cfg->items++; 3580914bffb6SAlexander V. Chernikov } 3581914bffb6SAlexander V. Chernikov 3582914bffb6SAlexander V. Chernikov return (0); 3583914bffb6SAlexander V. Chernikov } 3584914bffb6SAlexander V. Chernikov 3585914bffb6SAlexander V. Chernikov static int 3586914bffb6SAlexander V. Chernikov ta_prepare_del_fhash(struct ip_fw_chain *ch, struct tentry_info *tei, 3587914bffb6SAlexander V. Chernikov void *ta_buf) 3588914bffb6SAlexander V. Chernikov { 3589914bffb6SAlexander V. Chernikov struct ta_buf_fhash *tb; 3590914bffb6SAlexander V. Chernikov 3591914bffb6SAlexander V. Chernikov tb = (struct ta_buf_fhash *)ta_buf; 3592914bffb6SAlexander V. Chernikov 3593914bffb6SAlexander V. Chernikov return (tei_to_fhash_ent(tei, &tb->fe6.e)); 3594914bffb6SAlexander V. Chernikov } 3595914bffb6SAlexander V. Chernikov 3596914bffb6SAlexander V. Chernikov static int 3597914bffb6SAlexander V. Chernikov ta_del_fhash(void *ta_state, struct table_info *ti, struct tentry_info *tei, 3598b6ee846eSAlexander V. Chernikov void *ta_buf, uint32_t *pnum) 3599914bffb6SAlexander V. Chernikov { 3600914bffb6SAlexander V. Chernikov struct fhash_cfg *cfg; 3601914bffb6SAlexander V. Chernikov struct fhashbhead *head; 3602914bffb6SAlexander V. Chernikov struct fhashentry *ent, *tmp; 3603914bffb6SAlexander V. Chernikov struct ta_buf_fhash *tb; 3604914bffb6SAlexander V. Chernikov uint32_t hash; 3605914bffb6SAlexander V. Chernikov size_t sz; 3606914bffb6SAlexander V. Chernikov 3607914bffb6SAlexander V. Chernikov cfg = (struct fhash_cfg *)ta_state; 3608914bffb6SAlexander V. Chernikov tb = (struct ta_buf_fhash *)ta_buf; 3609914bffb6SAlexander V. Chernikov ent = &tb->fe6.e; 3610914bffb6SAlexander V. Chernikov 3611914bffb6SAlexander V. Chernikov head = cfg->head; 3612914bffb6SAlexander V. Chernikov hash = hash_flow_ent(ent, cfg->size); 3613914bffb6SAlexander V. Chernikov 3614914bffb6SAlexander V. Chernikov if (tei->subtype == AF_INET) 3615914bffb6SAlexander V. Chernikov sz = 2 * sizeof(struct in_addr); 3616914bffb6SAlexander V. Chernikov else 3617914bffb6SAlexander V. Chernikov sz = 2 * sizeof(struct in6_addr); 3618914bffb6SAlexander V. Chernikov 3619914bffb6SAlexander V. Chernikov /* Check for existence */ 3620914bffb6SAlexander V. Chernikov SLIST_FOREACH(tmp, &head[hash], next) { 3621648e8380SAlexander V. Chernikov if (cmp_flow_ent(tmp, ent, sz) == 0) 3622648e8380SAlexander V. Chernikov continue; 3623648e8380SAlexander V. Chernikov 3624914bffb6SAlexander V. Chernikov SLIST_REMOVE(&head[hash], tmp, fhashentry, next); 3625648e8380SAlexander V. Chernikov tei->value = tmp->value; 3626914bffb6SAlexander V. Chernikov *pnum = 1; 3627914bffb6SAlexander V. Chernikov cfg->items--; 3628648e8380SAlexander V. Chernikov tb->ent_ptr = tmp; 3629914bffb6SAlexander V. Chernikov return (0); 3630914bffb6SAlexander V. Chernikov } 3631914bffb6SAlexander V. Chernikov 3632914bffb6SAlexander V. Chernikov return (ENOENT); 3633914bffb6SAlexander V. Chernikov } 3634914bffb6SAlexander V. Chernikov 3635914bffb6SAlexander V. Chernikov static void 3636914bffb6SAlexander V. Chernikov ta_flush_fhash_entry(struct ip_fw_chain *ch, struct tentry_info *tei, 3637914bffb6SAlexander V. Chernikov void *ta_buf) 3638914bffb6SAlexander V. Chernikov { 3639914bffb6SAlexander V. Chernikov struct ta_buf_fhash *tb; 3640914bffb6SAlexander V. Chernikov 3641914bffb6SAlexander V. Chernikov tb = (struct ta_buf_fhash *)ta_buf; 3642914bffb6SAlexander V. Chernikov 3643914bffb6SAlexander V. Chernikov if (tb->ent_ptr != NULL) 3644914bffb6SAlexander V. Chernikov free(tb->ent_ptr, M_IPFW_TBL); 3645914bffb6SAlexander V. Chernikov } 3646914bffb6SAlexander V. Chernikov 3647914bffb6SAlexander V. Chernikov /* 3648914bffb6SAlexander V. Chernikov * Hash growing callbacks. 3649914bffb6SAlexander V. Chernikov */ 3650914bffb6SAlexander V. Chernikov 3651b6ee846eSAlexander V. Chernikov static int 3652301290bcSAlexander V. Chernikov ta_need_modify_fhash(void *ta_state, struct table_info *ti, uint32_t count, 3653b6ee846eSAlexander V. Chernikov uint64_t *pflags) 3654b6ee846eSAlexander V. Chernikov { 3655b6ee846eSAlexander V. Chernikov struct fhash_cfg *cfg; 3656b6ee846eSAlexander V. Chernikov 3657b6ee846eSAlexander V. Chernikov cfg = (struct fhash_cfg *)ta_state; 3658b6ee846eSAlexander V. Chernikov 3659b6ee846eSAlexander V. Chernikov if (cfg->items > cfg->size && cfg->size < 65536) { 3660b6ee846eSAlexander V. Chernikov *pflags = cfg->size * 2; 3661301290bcSAlexander V. Chernikov return (1); 3662b6ee846eSAlexander V. Chernikov } 3663b6ee846eSAlexander V. Chernikov 3664301290bcSAlexander V. Chernikov return (0); 3665b6ee846eSAlexander V. Chernikov } 3666b6ee846eSAlexander V. Chernikov 3667914bffb6SAlexander V. Chernikov /* 3668914bffb6SAlexander V. Chernikov * Allocate new, larger fhash. 3669914bffb6SAlexander V. Chernikov */ 3670914bffb6SAlexander V. Chernikov static int 3671914bffb6SAlexander V. Chernikov ta_prepare_mod_fhash(void *ta_buf, uint64_t *pflags) 3672914bffb6SAlexander V. Chernikov { 3673914bffb6SAlexander V. Chernikov struct mod_item *mi; 3674914bffb6SAlexander V. Chernikov struct fhashbhead *head; 3675*d821d364SPedro F. Giffuni u_int i; 3676914bffb6SAlexander V. Chernikov 3677914bffb6SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 3678914bffb6SAlexander V. Chernikov 3679914bffb6SAlexander V. Chernikov memset(mi, 0, sizeof(struct mod_item)); 3680914bffb6SAlexander V. Chernikov mi->size = *pflags; 3681914bffb6SAlexander V. Chernikov head = malloc(sizeof(struct fhashbhead) * mi->size, M_IPFW, 3682914bffb6SAlexander V. Chernikov M_WAITOK | M_ZERO); 3683914bffb6SAlexander V. Chernikov for (i = 0; i < mi->size; i++) 3684914bffb6SAlexander V. Chernikov SLIST_INIT(&head[i]); 3685914bffb6SAlexander V. Chernikov 3686914bffb6SAlexander V. Chernikov mi->main_ptr = head; 3687914bffb6SAlexander V. Chernikov 3688914bffb6SAlexander V. Chernikov return (0); 3689914bffb6SAlexander V. Chernikov } 3690914bffb6SAlexander V. Chernikov 3691914bffb6SAlexander V. Chernikov /* 3692914bffb6SAlexander V. Chernikov * Copy data from old runtime array to new one. 3693914bffb6SAlexander V. Chernikov */ 3694914bffb6SAlexander V. Chernikov static int 3695914bffb6SAlexander V. Chernikov ta_fill_mod_fhash(void *ta_state, struct table_info *ti, void *ta_buf, 3696914bffb6SAlexander V. Chernikov uint64_t *pflags) 3697914bffb6SAlexander V. Chernikov { 3698914bffb6SAlexander V. Chernikov 3699914bffb6SAlexander V. Chernikov /* In is not possible to do rehash if we're not holidng WLOCK. */ 3700914bffb6SAlexander V. Chernikov return (0); 3701914bffb6SAlexander V. Chernikov } 3702914bffb6SAlexander V. Chernikov 3703914bffb6SAlexander V. Chernikov /* 3704914bffb6SAlexander V. Chernikov * Switch old & new arrays. 3705914bffb6SAlexander V. Chernikov */ 3706301290bcSAlexander V. Chernikov static void 3707914bffb6SAlexander V. Chernikov ta_modify_fhash(void *ta_state, struct table_info *ti, void *ta_buf, 3708914bffb6SAlexander V. Chernikov uint64_t pflags) 3709914bffb6SAlexander V. Chernikov { 3710914bffb6SAlexander V. Chernikov struct mod_item *mi; 3711914bffb6SAlexander V. Chernikov struct fhash_cfg *cfg; 3712914bffb6SAlexander V. Chernikov struct fhashbhead *old_head, *new_head; 3713914bffb6SAlexander V. Chernikov struct fhashentry *ent, *ent_next; 3714914bffb6SAlexander V. Chernikov int i; 3715914bffb6SAlexander V. Chernikov uint32_t nhash; 3716914bffb6SAlexander V. Chernikov size_t old_size; 3717914bffb6SAlexander V. Chernikov 3718914bffb6SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 3719914bffb6SAlexander V. Chernikov cfg = (struct fhash_cfg *)ta_state; 3720914bffb6SAlexander V. Chernikov 3721914bffb6SAlexander V. Chernikov old_size = cfg->size; 3722914bffb6SAlexander V. Chernikov old_head = ti->state; 3723914bffb6SAlexander V. Chernikov 3724914bffb6SAlexander V. Chernikov new_head = (struct fhashbhead *)mi->main_ptr; 3725914bffb6SAlexander V. Chernikov for (i = 0; i < old_size; i++) { 3726914bffb6SAlexander V. Chernikov SLIST_FOREACH_SAFE(ent, &old_head[i], next, ent_next) { 3727914bffb6SAlexander V. Chernikov nhash = hash_flow_ent(ent, mi->size); 3728914bffb6SAlexander V. Chernikov SLIST_INSERT_HEAD(&new_head[nhash], ent, next); 3729914bffb6SAlexander V. Chernikov } 3730914bffb6SAlexander V. Chernikov } 3731914bffb6SAlexander V. Chernikov 3732914bffb6SAlexander V. Chernikov ti->state = new_head; 3733914bffb6SAlexander V. Chernikov ti->data = mi->size; 3734914bffb6SAlexander V. Chernikov cfg->head = new_head; 3735914bffb6SAlexander V. Chernikov cfg->size = mi->size; 3736914bffb6SAlexander V. Chernikov 3737914bffb6SAlexander V. Chernikov mi->main_ptr = old_head; 3738914bffb6SAlexander V. Chernikov } 3739914bffb6SAlexander V. Chernikov 3740914bffb6SAlexander V. Chernikov /* 3741914bffb6SAlexander V. Chernikov * Free unneded array. 3742914bffb6SAlexander V. Chernikov */ 3743914bffb6SAlexander V. Chernikov static void 3744914bffb6SAlexander V. Chernikov ta_flush_mod_fhash(void *ta_buf) 3745914bffb6SAlexander V. Chernikov { 3746914bffb6SAlexander V. Chernikov struct mod_item *mi; 3747914bffb6SAlexander V. Chernikov 3748914bffb6SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 3749914bffb6SAlexander V. Chernikov if (mi->main_ptr != NULL) 3750914bffb6SAlexander V. Chernikov free(mi->main_ptr, M_IPFW); 3751914bffb6SAlexander V. Chernikov } 3752914bffb6SAlexander V. Chernikov 3753914bffb6SAlexander V. Chernikov struct table_algo flow_hash = { 3754914bffb6SAlexander V. Chernikov .name = "flow:hash", 3755914bffb6SAlexander V. Chernikov .type = IPFW_TABLE_FLOW, 375657a1cf95SAlexander V. Chernikov .flags = TA_FLAG_DEFAULT, 375757a1cf95SAlexander V. Chernikov .ta_buf_size = sizeof(struct ta_buf_fhash), 3758914bffb6SAlexander V. Chernikov .init = ta_init_fhash, 3759914bffb6SAlexander V. Chernikov .destroy = ta_destroy_fhash, 3760914bffb6SAlexander V. Chernikov .prepare_add = ta_prepare_add_fhash, 3761914bffb6SAlexander V. Chernikov .prepare_del = ta_prepare_del_fhash, 3762914bffb6SAlexander V. Chernikov .add = ta_add_fhash, 3763914bffb6SAlexander V. Chernikov .del = ta_del_fhash, 3764914bffb6SAlexander V. Chernikov .flush_entry = ta_flush_fhash_entry, 3765914bffb6SAlexander V. Chernikov .foreach = ta_foreach_fhash, 3766914bffb6SAlexander V. Chernikov .dump_tentry = ta_dump_fhash_tentry, 3767914bffb6SAlexander V. Chernikov .find_tentry = ta_find_fhash_tentry, 37685f379342SAlexander V. Chernikov .dump_tinfo = ta_dump_fhash_tinfo, 3769301290bcSAlexander V. Chernikov .need_modify = ta_need_modify_fhash, 3770914bffb6SAlexander V. Chernikov .prepare_mod = ta_prepare_mod_fhash, 3771914bffb6SAlexander V. Chernikov .fill_mod = ta_fill_mod_fhash, 3772914bffb6SAlexander V. Chernikov .modify = ta_modify_fhash, 3773914bffb6SAlexander V. Chernikov .flush_mod = ta_flush_mod_fhash, 3774914bffb6SAlexander V. Chernikov }; 37753fe2ef91SAlexander V. Chernikov 3776d3b00c08SAlexander V. Chernikov /* 3777d3b00c08SAlexander V. Chernikov * Kernel fibs bindings. 3778d3b00c08SAlexander V. Chernikov * 3779d3b00c08SAlexander V. Chernikov * Implementation: 3780d3b00c08SAlexander V. Chernikov * 3781d3b00c08SAlexander V. Chernikov * Runtime part: 3782d3b00c08SAlexander V. Chernikov * - fully relies on route API 3783d3b00c08SAlexander V. Chernikov * - fib number is stored in ti->data 3784d3b00c08SAlexander V. Chernikov * 3785d3b00c08SAlexander V. Chernikov */ 3786d3b00c08SAlexander V. Chernikov 37879fe15d06SAlexander V. Chernikov static int ta_lookup_kfib(struct table_info *ti, void *key, uint32_t keylen, 37889fe15d06SAlexander V. Chernikov uint32_t *val); 37899fe15d06SAlexander V. Chernikov static int kfib_parse_opts(int *pfib, char *data); 37909fe15d06SAlexander V. Chernikov static void ta_print_kfib_config(void *ta_state, struct table_info *ti, 37919fe15d06SAlexander V. Chernikov char *buf, size_t bufsize); 37929fe15d06SAlexander V. Chernikov static int ta_init_kfib(struct ip_fw_chain *ch, void **ta_state, 37939fe15d06SAlexander V. Chernikov struct table_info *ti, char *data, uint8_t tflags); 37949fe15d06SAlexander V. Chernikov static void ta_destroy_kfib(void *ta_state, struct table_info *ti); 37959fe15d06SAlexander V. Chernikov static void ta_dump_kfib_tinfo(void *ta_state, struct table_info *ti, 37969fe15d06SAlexander V. Chernikov ipfw_ta_tinfo *tinfo); 37979fe15d06SAlexander V. Chernikov static int contigmask(uint8_t *p, int len); 37989fe15d06SAlexander V. Chernikov static int ta_dump_kfib_tentry(void *ta_state, struct table_info *ti, void *e, 37999fe15d06SAlexander V. Chernikov ipfw_obj_tentry *tent); 3800004d3e30SAlexander V. Chernikov static int ta_dump_kfib_tentry_int(struct sockaddr *paddr, 3801004d3e30SAlexander V. Chernikov struct sockaddr *pmask, ipfw_obj_tentry *tent); 38029fe15d06SAlexander V. Chernikov static int ta_find_kfib_tentry(void *ta_state, struct table_info *ti, 38039fe15d06SAlexander V. Chernikov ipfw_obj_tentry *tent); 38049fe15d06SAlexander V. Chernikov static void ta_foreach_kfib(void *ta_state, struct table_info *ti, 38059fe15d06SAlexander V. Chernikov ta_foreach_f *f, void *arg); 38069fe15d06SAlexander V. Chernikov 3807d3b00c08SAlexander V. Chernikov 3808d3b00c08SAlexander V. Chernikov static int 3809d3b00c08SAlexander V. Chernikov ta_lookup_kfib(struct table_info *ti, void *key, uint32_t keylen, 3810d3b00c08SAlexander V. Chernikov uint32_t *val) 3811d3b00c08SAlexander V. Chernikov { 3812004d3e30SAlexander V. Chernikov #ifdef INET 3813004d3e30SAlexander V. Chernikov struct nhop4_basic nh4; 3814004d3e30SAlexander V. Chernikov struct in_addr in; 3815004d3e30SAlexander V. Chernikov #endif 3816004d3e30SAlexander V. Chernikov #ifdef INET6 3817004d3e30SAlexander V. Chernikov struct nhop6_basic nh6; 3818004d3e30SAlexander V. Chernikov #endif 3819004d3e30SAlexander V. Chernikov int error; 3820d3b00c08SAlexander V. Chernikov 382189fc126aSAlexander V. Chernikov error = ENOENT; 3822004d3e30SAlexander V. Chernikov #ifdef INET 3823004d3e30SAlexander V. Chernikov if (keylen == 4) { 3824004d3e30SAlexander V. Chernikov in.s_addr = *(in_addr_t *)key; 3825004d3e30SAlexander V. Chernikov error = fib4_lookup_nh_basic(ti->data, 3826004d3e30SAlexander V. Chernikov in, 0, 0, &nh4); 3827004d3e30SAlexander V. Chernikov } 3828004d3e30SAlexander V. Chernikov #endif 3829004d3e30SAlexander V. Chernikov #ifdef INET6 3830004d3e30SAlexander V. Chernikov if (keylen == 6) 3831004d3e30SAlexander V. Chernikov error = fib6_lookup_nh_basic(ti->data, 3832004d3e30SAlexander V. Chernikov (struct in6_addr *)key, 0, 0, 0, &nh6); 3833004d3e30SAlexander V. Chernikov #endif 3834004d3e30SAlexander V. Chernikov 3835004d3e30SAlexander V. Chernikov if (error != 0) 3836d3b00c08SAlexander V. Chernikov return (0); 3837d3b00c08SAlexander V. Chernikov 3838d3b00c08SAlexander V. Chernikov *val = 0; 3839d3b00c08SAlexander V. Chernikov 3840d3b00c08SAlexander V. Chernikov return (1); 3841d3b00c08SAlexander V. Chernikov } 3842d3b00c08SAlexander V. Chernikov 3843d3b00c08SAlexander V. Chernikov /* Parse 'fib=%d' */ 3844d3b00c08SAlexander V. Chernikov static int 3845d3b00c08SAlexander V. Chernikov kfib_parse_opts(int *pfib, char *data) 3846d3b00c08SAlexander V. Chernikov { 3847d3b00c08SAlexander V. Chernikov char *pdel, *pend, *s; 3848d3b00c08SAlexander V. Chernikov int fibnum; 3849d3b00c08SAlexander V. Chernikov 3850d3b00c08SAlexander V. Chernikov if (data == NULL) 3851d3b00c08SAlexander V. Chernikov return (0); 3852d3b00c08SAlexander V. Chernikov if ((pdel = strchr(data, ' ')) == NULL) 3853d3b00c08SAlexander V. Chernikov return (0); 3854d3b00c08SAlexander V. Chernikov while (*pdel == ' ') 3855d3b00c08SAlexander V. Chernikov pdel++; 3856d3b00c08SAlexander V. Chernikov if (strncmp(pdel, "fib=", 4) != 0) 3857d3b00c08SAlexander V. Chernikov return (EINVAL); 3858d3b00c08SAlexander V. Chernikov if ((s = strchr(pdel, ' ')) != NULL) 3859d3b00c08SAlexander V. Chernikov *s++ = '\0'; 3860d3b00c08SAlexander V. Chernikov 3861d3b00c08SAlexander V. Chernikov pdel += 4; 3862d3b00c08SAlexander V. Chernikov /* Need \d+ */ 3863d3b00c08SAlexander V. Chernikov fibnum = strtol(pdel, &pend, 10); 3864d3b00c08SAlexander V. Chernikov if (*pend != '\0') 3865d3b00c08SAlexander V. Chernikov return (EINVAL); 3866d3b00c08SAlexander V. Chernikov 3867d3b00c08SAlexander V. Chernikov *pfib = fibnum; 3868d3b00c08SAlexander V. Chernikov 3869d3b00c08SAlexander V. Chernikov return (0); 3870d3b00c08SAlexander V. Chernikov } 3871d3b00c08SAlexander V. Chernikov 3872d3b00c08SAlexander V. Chernikov static void 3873d3b00c08SAlexander V. Chernikov ta_print_kfib_config(void *ta_state, struct table_info *ti, char *buf, 3874d3b00c08SAlexander V. Chernikov size_t bufsize) 3875d3b00c08SAlexander V. Chernikov { 3876d3b00c08SAlexander V. Chernikov 3877d3b00c08SAlexander V. Chernikov if (ti->data != 0) 3878c21034b7SAlexander V. Chernikov snprintf(buf, bufsize, "%s fib=%lu", "addr:kfib", ti->data); 3879d3b00c08SAlexander V. Chernikov else 3880c21034b7SAlexander V. Chernikov snprintf(buf, bufsize, "%s", "addr:kfib"); 3881d3b00c08SAlexander V. Chernikov } 3882d3b00c08SAlexander V. Chernikov 3883d3b00c08SAlexander V. Chernikov static int 3884d3b00c08SAlexander V. Chernikov ta_init_kfib(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti, 3885d3b00c08SAlexander V. Chernikov char *data, uint8_t tflags) 3886d3b00c08SAlexander V. Chernikov { 3887d3b00c08SAlexander V. Chernikov int error, fibnum; 3888d3b00c08SAlexander V. Chernikov 3889d3b00c08SAlexander V. Chernikov fibnum = 0; 3890d3b00c08SAlexander V. Chernikov if ((error = kfib_parse_opts(&fibnum, data)) != 0) 3891d3b00c08SAlexander V. Chernikov return (error); 3892d3b00c08SAlexander V. Chernikov 3893d3b00c08SAlexander V. Chernikov if (fibnum >= rt_numfibs) 3894d3b00c08SAlexander V. Chernikov return (E2BIG); 3895d3b00c08SAlexander V. Chernikov 3896d3b00c08SAlexander V. Chernikov ti->data = fibnum; 3897d3b00c08SAlexander V. Chernikov ti->lookup = ta_lookup_kfib; 3898d3b00c08SAlexander V. Chernikov 3899d3b00c08SAlexander V. Chernikov return (0); 3900d3b00c08SAlexander V. Chernikov } 3901d3b00c08SAlexander V. Chernikov 3902d3b00c08SAlexander V. Chernikov /* 3903d3b00c08SAlexander V. Chernikov * Destroys table @ti 3904d3b00c08SAlexander V. Chernikov */ 3905d3b00c08SAlexander V. Chernikov static void 3906d3b00c08SAlexander V. Chernikov ta_destroy_kfib(void *ta_state, struct table_info *ti) 3907d3b00c08SAlexander V. Chernikov { 3908d3b00c08SAlexander V. Chernikov 3909d3b00c08SAlexander V. Chernikov } 3910d3b00c08SAlexander V. Chernikov 3911d3b00c08SAlexander V. Chernikov /* 3912d3b00c08SAlexander V. Chernikov * Provide algo-specific table info 3913d3b00c08SAlexander V. Chernikov */ 3914d3b00c08SAlexander V. Chernikov static void 3915d3b00c08SAlexander V. Chernikov ta_dump_kfib_tinfo(void *ta_state, struct table_info *ti, ipfw_ta_tinfo *tinfo) 3916d3b00c08SAlexander V. Chernikov { 3917d3b00c08SAlexander V. Chernikov 3918d3b00c08SAlexander V. Chernikov tinfo->flags = IPFW_TATFLAGS_AFDATA; 3919d3b00c08SAlexander V. Chernikov tinfo->taclass4 = IPFW_TACLASS_RADIX; 3920d3b00c08SAlexander V. Chernikov tinfo->count4 = 0; 3921d3b00c08SAlexander V. Chernikov tinfo->itemsize4 = sizeof(struct rtentry); 3922d3b00c08SAlexander V. Chernikov tinfo->taclass6 = IPFW_TACLASS_RADIX; 3923d3b00c08SAlexander V. Chernikov tinfo->count6 = 0; 3924d3b00c08SAlexander V. Chernikov tinfo->itemsize6 = sizeof(struct rtentry); 3925d3b00c08SAlexander V. Chernikov } 3926d3b00c08SAlexander V. Chernikov 3927d3b00c08SAlexander V. Chernikov static int 3928d3b00c08SAlexander V. Chernikov contigmask(uint8_t *p, int len) 3929d3b00c08SAlexander V. Chernikov { 3930d3b00c08SAlexander V. Chernikov int i, n; 3931d3b00c08SAlexander V. Chernikov 3932d3b00c08SAlexander V. Chernikov for (i = 0; i < len ; i++) 3933d3b00c08SAlexander V. Chernikov if ( (p[i/8] & (1 << (7 - (i%8)))) == 0) /* first bit unset */ 3934d3b00c08SAlexander V. Chernikov break; 3935d3b00c08SAlexander V. Chernikov for (n= i + 1; n < len; n++) 3936d3b00c08SAlexander V. Chernikov if ( (p[n/8] & (1 << (7 - (n % 8)))) != 0) 3937d3b00c08SAlexander V. Chernikov return (-1); /* mask not contiguous */ 3938d3b00c08SAlexander V. Chernikov return (i); 3939d3b00c08SAlexander V. Chernikov } 3940d3b00c08SAlexander V. Chernikov 3941d3b00c08SAlexander V. Chernikov 3942d3b00c08SAlexander V. Chernikov static int 3943d3b00c08SAlexander V. Chernikov ta_dump_kfib_tentry(void *ta_state, struct table_info *ti, void *e, 3944d3b00c08SAlexander V. Chernikov ipfw_obj_tentry *tent) 3945d3b00c08SAlexander V. Chernikov { 3946d3b00c08SAlexander V. Chernikov struct rtentry *rte; 3947004d3e30SAlexander V. Chernikov 3948004d3e30SAlexander V. Chernikov rte = (struct rtentry *)e; 3949004d3e30SAlexander V. Chernikov 3950004d3e30SAlexander V. Chernikov return ta_dump_kfib_tentry_int(rt_key(rte), rt_mask(rte), tent); 3951004d3e30SAlexander V. Chernikov } 3952004d3e30SAlexander V. Chernikov 3953004d3e30SAlexander V. Chernikov static int 3954004d3e30SAlexander V. Chernikov ta_dump_kfib_tentry_int(struct sockaddr *paddr, struct sockaddr *pmask, 3955004d3e30SAlexander V. Chernikov ipfw_obj_tentry *tent) 3956004d3e30SAlexander V. Chernikov { 3957d699ee2dSAlexander V. Chernikov #ifdef INET 3958d3b00c08SAlexander V. Chernikov struct sockaddr_in *addr, *mask; 3959d699ee2dSAlexander V. Chernikov #endif 3960d699ee2dSAlexander V. Chernikov #ifdef INET6 3961d3b00c08SAlexander V. Chernikov struct sockaddr_in6 *addr6, *mask6; 3962d699ee2dSAlexander V. Chernikov #endif 3963d3b00c08SAlexander V. Chernikov int len; 3964d3b00c08SAlexander V. Chernikov 3965d3b00c08SAlexander V. Chernikov len = 0; 3966d3b00c08SAlexander V. Chernikov 3967d3b00c08SAlexander V. Chernikov /* Guess IPv4/IPv6 radix by sockaddr family */ 3968d699ee2dSAlexander V. Chernikov #ifdef INET 3969004d3e30SAlexander V. Chernikov if (paddr->sa_family == AF_INET) { 3970004d3e30SAlexander V. Chernikov addr = (struct sockaddr_in *)paddr; 3971004d3e30SAlexander V. Chernikov mask = (struct sockaddr_in *)pmask; 3972d3b00c08SAlexander V. Chernikov tent->k.addr.s_addr = addr->sin_addr.s_addr; 3973d3b00c08SAlexander V. Chernikov len = 32; 3974d3b00c08SAlexander V. Chernikov if (mask != NULL) 3975d3b00c08SAlexander V. Chernikov len = contigmask((uint8_t *)&mask->sin_addr, 32); 3976d3b00c08SAlexander V. Chernikov if (len == -1) 3977d3b00c08SAlexander V. Chernikov len = 0; 3978d3b00c08SAlexander V. Chernikov tent->masklen = len; 3979d3b00c08SAlexander V. Chernikov tent->subtype = AF_INET; 39800cba2b28SAlexander V. Chernikov tent->v.kidx = 0; /* Do we need to put GW here? */ 3981d699ee2dSAlexander V. Chernikov } 3982d699ee2dSAlexander V. Chernikov #endif 3983d3b00c08SAlexander V. Chernikov #ifdef INET6 3984004d3e30SAlexander V. Chernikov if (paddr->sa_family == AF_INET6) { 3985004d3e30SAlexander V. Chernikov addr6 = (struct sockaddr_in6 *)paddr; 3986004d3e30SAlexander V. Chernikov mask6 = (struct sockaddr_in6 *)pmask; 3987ba3e1361SAndrey V. Elsukov memcpy(&tent->k.addr6, &addr6->sin6_addr, 3988ba3e1361SAndrey V. Elsukov sizeof(struct in6_addr)); 3989d3b00c08SAlexander V. Chernikov len = 128; 3990d3b00c08SAlexander V. Chernikov if (mask6 != NULL) 3991d3b00c08SAlexander V. Chernikov len = contigmask((uint8_t *)&mask6->sin6_addr, 128); 3992d3b00c08SAlexander V. Chernikov if (len == -1) 3993d3b00c08SAlexander V. Chernikov len = 0; 3994d3b00c08SAlexander V. Chernikov tent->masklen = len; 3995d3b00c08SAlexander V. Chernikov tent->subtype = AF_INET6; 39960cba2b28SAlexander V. Chernikov tent->v.kidx = 0; 3997d3b00c08SAlexander V. Chernikov } 3998d699ee2dSAlexander V. Chernikov #endif 3999d3b00c08SAlexander V. Chernikov 4000d3b00c08SAlexander V. Chernikov return (0); 4001d3b00c08SAlexander V. Chernikov } 4002d3b00c08SAlexander V. Chernikov 4003d3b00c08SAlexander V. Chernikov static int 4004d3b00c08SAlexander V. Chernikov ta_find_kfib_tentry(void *ta_state, struct table_info *ti, 4005d3b00c08SAlexander V. Chernikov ipfw_obj_tentry *tent) 4006d3b00c08SAlexander V. Chernikov { 4007004d3e30SAlexander V. Chernikov struct rt_addrinfo info; 4008004d3e30SAlexander V. Chernikov struct sockaddr_in6 key6, dst6, mask6; 4009004d3e30SAlexander V. Chernikov struct sockaddr *dst, *key, *mask; 4010004d3e30SAlexander V. Chernikov 4011004d3e30SAlexander V. Chernikov /* Prepare sockaddr for prefix/mask and info */ 4012004d3e30SAlexander V. Chernikov bzero(&dst6, sizeof(dst6)); 4013004d3e30SAlexander V. Chernikov dst6.sin6_len = sizeof(dst6); 4014004d3e30SAlexander V. Chernikov dst = (struct sockaddr *)&dst6; 4015004d3e30SAlexander V. Chernikov bzero(&mask6, sizeof(mask6)); 4016004d3e30SAlexander V. Chernikov mask6.sin6_len = sizeof(mask6); 4017004d3e30SAlexander V. Chernikov mask = (struct sockaddr *)&mask6; 4018004d3e30SAlexander V. Chernikov 4019004d3e30SAlexander V. Chernikov bzero(&info, sizeof(info)); 4020004d3e30SAlexander V. Chernikov info.rti_info[RTAX_DST] = dst; 4021004d3e30SAlexander V. Chernikov info.rti_info[RTAX_NETMASK] = mask; 4022004d3e30SAlexander V. Chernikov 4023004d3e30SAlexander V. Chernikov /* Prepare the lookup key */ 4024004d3e30SAlexander V. Chernikov bzero(&key6, sizeof(key6)); 4025004d3e30SAlexander V. Chernikov key6.sin6_family = tent->subtype; 4026004d3e30SAlexander V. Chernikov key = (struct sockaddr *)&key6; 4027d3b00c08SAlexander V. Chernikov 4028d3b00c08SAlexander V. Chernikov if (tent->subtype == AF_INET) { 4029004d3e30SAlexander V. Chernikov ((struct sockaddr_in *)&key6)->sin_addr = tent->k.addr; 4030004d3e30SAlexander V. Chernikov key6.sin6_len = sizeof(struct sockaddr_in); 4031d3b00c08SAlexander V. Chernikov } else { 4032004d3e30SAlexander V. Chernikov key6.sin6_addr = tent->k.addr6; 4033004d3e30SAlexander V. Chernikov key6.sin6_len = sizeof(struct sockaddr_in6); 4034d3b00c08SAlexander V. Chernikov } 4035d3b00c08SAlexander V. Chernikov 4036004d3e30SAlexander V. Chernikov if (rib_lookup_info(ti->data, key, 0, 0, &info) != 0) 4037d3b00c08SAlexander V. Chernikov return (ENOENT); 4038004d3e30SAlexander V. Chernikov if ((info.rti_addrs & RTA_NETMASK) == 0) 4039004d3e30SAlexander V. Chernikov mask = NULL; 4040004d3e30SAlexander V. Chernikov 4041004d3e30SAlexander V. Chernikov ta_dump_kfib_tentry_int(dst, mask, tent); 4042004d3e30SAlexander V. Chernikov 4043004d3e30SAlexander V. Chernikov return (0); 4044d3b00c08SAlexander V. Chernikov } 4045d3b00c08SAlexander V. Chernikov 4046d3b00c08SAlexander V. Chernikov static void 4047d3b00c08SAlexander V. Chernikov ta_foreach_kfib(void *ta_state, struct table_info *ti, ta_foreach_f *f, 4048d3b00c08SAlexander V. Chernikov void *arg) 4049d3b00c08SAlexander V. Chernikov { 405061eee0e2SAlexander V. Chernikov struct rib_head *rh; 4051d3b00c08SAlexander V. Chernikov int error; 4052d3b00c08SAlexander V. Chernikov 405361eee0e2SAlexander V. Chernikov rh = rt_tables_get_rnh(ti->data, AF_INET); 405461eee0e2SAlexander V. Chernikov if (rh != NULL) { 405561eee0e2SAlexander V. Chernikov RIB_RLOCK(rh); 405661eee0e2SAlexander V. Chernikov error = rh->rnh_walktree(&rh->head, (walktree_f_t *)f, arg); 405761eee0e2SAlexander V. Chernikov RIB_RUNLOCK(rh); 4058d3b00c08SAlexander V. Chernikov } 4059d3b00c08SAlexander V. Chernikov 406061eee0e2SAlexander V. Chernikov rh = rt_tables_get_rnh(ti->data, AF_INET6); 406161eee0e2SAlexander V. Chernikov if (rh != NULL) { 406261eee0e2SAlexander V. Chernikov RIB_RLOCK(rh); 406361eee0e2SAlexander V. Chernikov error = rh->rnh_walktree(&rh->head, (walktree_f_t *)f, arg); 406461eee0e2SAlexander V. Chernikov RIB_RUNLOCK(rh); 4065d3b00c08SAlexander V. Chernikov } 4066d3b00c08SAlexander V. Chernikov } 4067d3b00c08SAlexander V. Chernikov 4068c21034b7SAlexander V. Chernikov struct table_algo addr_kfib = { 4069c21034b7SAlexander V. Chernikov .name = "addr:kfib", 4070c21034b7SAlexander V. Chernikov .type = IPFW_TABLE_ADDR, 4071d3b00c08SAlexander V. Chernikov .flags = TA_FLAG_READONLY, 4072d3b00c08SAlexander V. Chernikov .ta_buf_size = 0, 4073d3b00c08SAlexander V. Chernikov .init = ta_init_kfib, 4074d3b00c08SAlexander V. Chernikov .destroy = ta_destroy_kfib, 4075d3b00c08SAlexander V. Chernikov .foreach = ta_foreach_kfib, 4076d3b00c08SAlexander V. Chernikov .dump_tentry = ta_dump_kfib_tentry, 4077d3b00c08SAlexander V. Chernikov .find_tentry = ta_find_kfib_tentry, 4078d3b00c08SAlexander V. Chernikov .dump_tinfo = ta_dump_kfib_tinfo, 4079d3b00c08SAlexander V. Chernikov .print_config = ta_print_kfib_config, 4080d3b00c08SAlexander V. Chernikov }; 4081d3b00c08SAlexander V. Chernikov 40829f7d47b0SAlexander V. Chernikov void 40830b565ac0SAlexander V. Chernikov ipfw_table_algo_init(struct ip_fw_chain *ch) 40849f7d47b0SAlexander V. Chernikov { 40850b565ac0SAlexander V. Chernikov size_t sz; 40860b565ac0SAlexander V. Chernikov 40879f7d47b0SAlexander V. Chernikov /* 40889f7d47b0SAlexander V. Chernikov * Register all algorithms presented here. 40899f7d47b0SAlexander V. Chernikov */ 40900b565ac0SAlexander V. Chernikov sz = sizeof(struct table_algo); 4091c21034b7SAlexander V. Chernikov ipfw_add_table_algo(ch, &addr_radix, sz, &addr_radix.idx); 4092c21034b7SAlexander V. Chernikov ipfw_add_table_algo(ch, &addr_hash, sz, &addr_hash.idx); 40930b565ac0SAlexander V. Chernikov ipfw_add_table_algo(ch, &iface_idx, sz, &iface_idx.idx); 4094b23d5de9SAlexander V. Chernikov ipfw_add_table_algo(ch, &number_array, sz, &number_array.idx); 4095914bffb6SAlexander V. Chernikov ipfw_add_table_algo(ch, &flow_hash, sz, &flow_hash.idx); 4096c21034b7SAlexander V. Chernikov ipfw_add_table_algo(ch, &addr_kfib, sz, &addr_kfib.idx); 40979f7d47b0SAlexander V. Chernikov } 40989f7d47b0SAlexander V. Chernikov 40999f7d47b0SAlexander V. Chernikov void 41000b565ac0SAlexander V. Chernikov ipfw_table_algo_destroy(struct ip_fw_chain *ch) 41019f7d47b0SAlexander V. Chernikov { 41020b565ac0SAlexander V. Chernikov 4103c21034b7SAlexander V. Chernikov ipfw_del_table_algo(ch, addr_radix.idx); 4104c21034b7SAlexander V. Chernikov ipfw_del_table_algo(ch, addr_hash.idx); 41050b565ac0SAlexander V. Chernikov ipfw_del_table_algo(ch, iface_idx.idx); 4106b23d5de9SAlexander V. Chernikov ipfw_del_table_algo(ch, number_array.idx); 4107914bffb6SAlexander V. Chernikov ipfw_del_table_algo(ch, flow_hash.idx); 4108c21034b7SAlexander V. Chernikov ipfw_del_table_algo(ch, addr_kfib.idx); 41099f7d47b0SAlexander V. Chernikov } 41109f7d47b0SAlexander V. Chernikov 41119f7d47b0SAlexander V. Chernikov 4112